Commit be88751f authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull misc filesystem updates from Jan Kara:
 "udf, ext2, quota, fsnotify fixes & cleanups:

   - udf fixes for handling of media without uid/gid

   - udf fixes for some corner cases in parsing of volume recognition
     sequence

   - improvements of fsnotify handling of ENOMEM

   - new ioctl to allow setting of watch descriptor id for inotify (for
     checkpoint - restart)

   - small ext2, reiserfs, quota cleanups"

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  quota: Kill an unused extern entry form quota.h
  reiserfs: Remove VLA from fs/reiserfs/reiserfs.h
  udf: fix potential refcnt problem of nls module
  ext2: change return code to -ENOMEM when failing memory allocation
  udf: Do not mark possibly inconsistent filesystems as closed
  fsnotify: Let userspace know about lost events due to ENOMEM
  fanotify: Avoid lost events due to ENOMEM for unlimited queues
  udf: Remove never implemented mount options
  udf: Update mount option documentation
  udf: Provide saner default for invalid uid / gid
  udf: Clean up handling of invalid uid/gid
  udf: Apply uid/gid mount options also to new inodes & chown
  udf: Ignore [ug]id=ignore mount options
  udf: Fix handling of Partition Descriptors
  udf: Unify common handling of descriptors
  udf: Convert descriptor index definitions to enum
  udf: Allow volume descriptor sequence to be terminated by unrecorded block
  udf: Simplify handling of Volume Descriptor Pointers
  udf: Fix off-by-one in volume descriptor sequence length
  inotify: Extend ioctl to allow to request id of new watch descriptor
parents 5e4d6597 b91ed9d8
...@@ -36,18 +36,14 @@ The following mount options are supported: ...@@ -36,18 +36,14 @@ The following mount options are supported:
iocharset= Set the NLS character set iocharset= Set the NLS character set
The uid= and gid= options need a bit more explaining. They will accept a The uid= and gid= options need a bit more explaining. They will accept a
decimal numeric value which will be used as the default ID for that mount. decimal numeric value and all inodes on that mount will then appear as
They will also accept the string "ignore" and "forget". For files on the disk belonging to that uid and gid. Mount options also accept the string "forget".
that are owned by nobody ( -1 ), they will instead look as if they are owned The forget option causes all IDs to be written to disk as -1 which is a way
by the default ID. The ignore option causes the default ID to override all of UDF standard to indicate that IDs are not supported for these files .
IDs on the disk, not just -1. The forget option causes all IDs to be written
to disk as -1, so when the media is later remounted, they will appear to be
owned by whatever default ID it is mounted with at that time.
For typical desktop use of removable media, you should set the ID to that For typical desktop use of removable media, you should set the ID to that of
of the interactively logged on user, and also specify both the forget and the interactively logged on user, and also specify the forget option. This way
ignore options. This way the interactive user will always see the files the interactive user will always see the files on the disk as belonging to him.
on the disk as belonging to him.
The remaining are for debugging and disaster recovery: The remaining are for debugging and disaster recovery:
...@@ -57,16 +53,8 @@ The following expect a offset from 0. ...@@ -57,16 +53,8 @@ The following expect a offset from 0.
session= Set the CDROM session (default= last session) session= Set the CDROM session (default= last session)
anchor= Override standard anchor location. (default= 256) anchor= Override standard anchor location. (default= 256)
volume= Override the VolumeDesc location. (unused)
partition= Override the PartitionDesc location. (unused)
lastblock= Set the last block of the filesystem/ lastblock= Set the last block of the filesystem/
The following expect a offset from the partition root.
fileset= Override the fileset block location. (unused)
rootdir= Override the root directory location. (unused)
WARNING: overriding the rootdir to a non-directory may
yield highly unpredictable results.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
......
...@@ -827,7 +827,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -827,7 +827,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
unsigned long logic_sb_block; unsigned long logic_sb_block;
unsigned long offset = 0; unsigned long offset = 0;
unsigned long def_mount_opts; unsigned long def_mount_opts;
long ret = -EINVAL; long ret = -ENOMEM;
int blocksize = BLOCK_SIZE; int blocksize = BLOCK_SIZE;
int db_count; int db_count;
int i, j; int i, j;
...@@ -835,7 +835,6 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -835,7 +835,6 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
int err; int err;
struct ext2_mount_options opts; struct ext2_mount_options opts;
err = -ENOMEM;
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi) if (!sbi)
goto failed; goto failed;
...@@ -851,6 +850,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -851,6 +850,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
sbi->s_daxdev = dax_dev; sbi->s_daxdev = dax_dev;
spin_lock_init(&sbi->s_lock); spin_lock_init(&sbi->s_lock);
ret = -EINVAL;
/* /*
* See what the current blocksize for the device is, and * See what the current blocksize for the device is, and
......
...@@ -139,23 +139,32 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark, ...@@ -139,23 +139,32 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
return false; return false;
} }
struct fanotify_event_info *fanotify_alloc_event(struct inode *inode, u32 mask, struct fanotify_event_info *fanotify_alloc_event(struct fsnotify_group *group,
struct inode *inode, u32 mask,
const struct path *path) const struct path *path)
{ {
struct fanotify_event_info *event; struct fanotify_event_info *event;
gfp_t gfp = GFP_KERNEL;
/*
* For queues with unlimited length lost events are not expected and
* can possibly have security implications. Avoid losing events when
* memory is short.
*/
if (group->max_events == UINT_MAX)
gfp |= __GFP_NOFAIL;
if (fanotify_is_perm_event(mask)) { if (fanotify_is_perm_event(mask)) {
struct fanotify_perm_event_info *pevent; struct fanotify_perm_event_info *pevent;
pevent = kmem_cache_alloc(fanotify_perm_event_cachep, pevent = kmem_cache_alloc(fanotify_perm_event_cachep, gfp);
GFP_KERNEL);
if (!pevent) if (!pevent)
return NULL; return NULL;
event = &pevent->fae; event = &pevent->fae;
pevent->response = 0; pevent->response = 0;
goto init; goto init;
} }
event = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL); event = kmem_cache_alloc(fanotify_event_cachep, gfp);
if (!event) if (!event)
return NULL; return NULL;
init: __maybe_unused init: __maybe_unused
...@@ -210,10 +219,17 @@ static int fanotify_handle_event(struct fsnotify_group *group, ...@@ -210,10 +219,17 @@ static int fanotify_handle_event(struct fsnotify_group *group,
return 0; return 0;
} }
event = fanotify_alloc_event(inode, mask, data); event = fanotify_alloc_event(group, inode, mask, data);
ret = -ENOMEM; ret = -ENOMEM;
if (unlikely(!event)) if (unlikely(!event)) {
/*
* We don't queue overflow events for permission events as
* there the access is denied and so no event is in fact lost.
*/
if (!fanotify_is_perm_event(mask))
fsnotify_queue_overflow(group);
goto finish; goto finish;
}
fsn_event = &event->fse; fsn_event = &event->fse;
ret = fsnotify_add_event(group, fsn_event, fanotify_merge); ret = fsnotify_add_event(group, fsn_event, fanotify_merge);
......
...@@ -52,5 +52,6 @@ static inline struct fanotify_event_info *FANOTIFY_E(struct fsnotify_event *fse) ...@@ -52,5 +52,6 @@ static inline struct fanotify_event_info *FANOTIFY_E(struct fsnotify_event *fse)
return container_of(fse, struct fanotify_event_info, fse); return container_of(fse, struct fanotify_event_info, fse);
} }
struct fanotify_event_info *fanotify_alloc_event(struct inode *inode, u32 mask, struct fanotify_event_info *fanotify_alloc_event(struct fsnotify_group *group,
struct inode *inode, u32 mask,
const struct path *path); const struct path *path);
...@@ -757,7 +757,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) ...@@ -757,7 +757,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
group->fanotify_data.user = user; group->fanotify_data.user = user;
atomic_inc(&user->fanotify_listeners); atomic_inc(&user->fanotify_listeners);
oevent = fanotify_alloc_event(NULL, FS_Q_OVERFLOW, NULL); oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL);
if (unlikely(!oevent)) { if (unlikely(!oevent)) {
fd = -ENOMEM; fd = -ENOMEM;
goto out_destroy_group; goto out_destroy_group;
......
...@@ -99,8 +99,14 @@ int inotify_handle_event(struct fsnotify_group *group, ...@@ -99,8 +99,14 @@ int inotify_handle_event(struct fsnotify_group *group,
fsn_mark); fsn_mark);
event = kmalloc(alloc_len, GFP_KERNEL); event = kmalloc(alloc_len, GFP_KERNEL);
if (unlikely(!event)) if (unlikely(!event)) {
/*
* Treat lost event due to ENOMEM the same way as queue
* overflow to let userspace know event was lost.
*/
fsnotify_queue_overflow(group);
return -ENOMEM; return -ENOMEM;
}
fsn_event = &event->fse; fsn_event = &event->fse;
fsnotify_init_event(fsn_event, inode, mask); fsnotify_init_event(fsn_event, inode, mask);
......
...@@ -307,6 +307,20 @@ static long inotify_ioctl(struct file *file, unsigned int cmd, ...@@ -307,6 +307,20 @@ static long inotify_ioctl(struct file *file, unsigned int cmd,
spin_unlock(&group->notification_lock); spin_unlock(&group->notification_lock);
ret = put_user(send_len, (int __user *) p); ret = put_user(send_len, (int __user *) p);
break; break;
#ifdef CONFIG_CHECKPOINT_RESTORE
case INOTIFY_IOC_SETNEXTWD:
ret = -EINVAL;
if (arg >= 1 && arg <= INT_MAX) {
struct inotify_group_private_data *data;
data = &group->inotify_data;
spin_lock(&data->idr_lock);
idr_set_cursor(&data->idr, (unsigned int)arg);
spin_unlock(&data->idr_lock);
ret = 0;
}
break;
#endif /* CONFIG_CHECKPOINT_RESTORE */
} }
return ret; return ret;
......
...@@ -111,7 +111,8 @@ int fsnotify_add_event(struct fsnotify_group *group, ...@@ -111,7 +111,8 @@ int fsnotify_add_event(struct fsnotify_group *group,
return 2; return 2;
} }
if (group->q_len >= group->max_events) { if (event == group->overflow_event ||
group->q_len >= group->max_events) {
ret = 2; ret = 2;
/* Queue overflow event only if it isn't already queued */ /* Queue overflow event only if it isn't already queued */
if (!list_empty(&group->overflow_event->list)) { if (!list_empty(&group->overflow_event->list)) {
......
...@@ -1916,7 +1916,7 @@ struct reiserfs_de_head { ...@@ -1916,7 +1916,7 @@ struct reiserfs_de_head {
/* empty directory contains two entries "." and ".." and their headers */ /* empty directory contains two entries "." and ".." and their headers */
#define EMPTY_DIR_SIZE \ #define EMPTY_DIR_SIZE \
(DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen (".."))) (DEH_SIZE * 2 + ROUND_UP (sizeof(".") - 1) + ROUND_UP (sizeof("..") - 1))
/* old format directories have this size when empty */ /* old format directories have this size when empty */
#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3) #define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3)
......
...@@ -257,12 +257,22 @@ const struct file_operations udf_file_operations = { ...@@ -257,12 +257,22 @@ const struct file_operations udf_file_operations = {
static int udf_setattr(struct dentry *dentry, struct iattr *attr) static int udf_setattr(struct dentry *dentry, struct iattr *attr)
{ {
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
struct super_block *sb = inode->i_sb;
int error; int error;
error = setattr_prepare(dentry, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;
if ((attr->ia_valid & ATTR_UID) &&
UDF_QUERY_FLAG(sb, UDF_FLAG_UID_SET) &&
!uid_eq(attr->ia_uid, UDF_SB(sb)->s_uid))
return -EPERM;
if ((attr->ia_valid & ATTR_GID) &&
UDF_QUERY_FLAG(sb, UDF_FLAG_GID_SET) &&
!gid_eq(attr->ia_gid, UDF_SB(sb)->s_gid))
return -EPERM;
if ((attr->ia_valid & ATTR_SIZE) && if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) { attr->ia_size != i_size_read(inode)) {
error = udf_setsize(inode, attr->ia_size); error = udf_setsize(inode, attr->ia_size);
......
...@@ -104,6 +104,10 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode) ...@@ -104,6 +104,10 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode)
} }
inode_init_owner(inode, dir, mode); inode_init_owner(inode, dir, mode);
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_SET))
inode->i_uid = sbi->s_uid;
if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_SET))
inode->i_gid = sbi->s_gid;
iinfo->i_location.logicalBlockNum = block; iinfo->i_location.logicalBlockNum = block;
iinfo->i_location.partitionReferenceNum = iinfo->i_location.partitionReferenceNum =
......
...@@ -1275,6 +1275,7 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode) ...@@ -1275,6 +1275,7 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode)
unsigned int indirections = 0; unsigned int indirections = 0;
int bs = inode->i_sb->s_blocksize; int bs = inode->i_sb->s_blocksize;
int ret = -EIO; int ret = -EIO;
uint32_t uid, gid;
reread: reread:
if (iloc->partitionReferenceNum >= sbi->s_partitions) { if (iloc->partitionReferenceNum >= sbi->s_partitions) {
...@@ -1400,17 +1401,19 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode) ...@@ -1400,17 +1401,19 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode)
ret = -EIO; ret = -EIO;
read_lock(&sbi->s_cred_lock); read_lock(&sbi->s_cred_lock);
i_uid_write(inode, le32_to_cpu(fe->uid)); uid = le32_to_cpu(fe->uid);
if (!uid_valid(inode->i_uid) || if (uid == UDF_INVALID_ID ||
UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_IGNORE) ||
UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_SET)) UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_SET))
inode->i_uid = UDF_SB(inode->i_sb)->s_uid; inode->i_uid = sbi->s_uid;
else
i_uid_write(inode, uid);
i_gid_write(inode, le32_to_cpu(fe->gid)); gid = le32_to_cpu(fe->gid);
if (!gid_valid(inode->i_gid) || if (gid == UDF_INVALID_ID ||
UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_IGNORE) ||
UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_SET)) UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_SET))
inode->i_gid = UDF_SB(inode->i_sb)->s_gid; inode->i_gid = sbi->s_gid;
else
i_gid_write(inode, gid);
if (fe->icbTag.fileType != ICBTAG_FILE_TYPE_DIRECTORY && if (fe->icbTag.fileType != ICBTAG_FILE_TYPE_DIRECTORY &&
sbi->s_fmode != UDF_INVALID_MODE) sbi->s_fmode != UDF_INVALID_MODE)
...@@ -1655,12 +1658,12 @@ static int udf_update_inode(struct inode *inode, int do_sync) ...@@ -1655,12 +1658,12 @@ static int udf_update_inode(struct inode *inode, int do_sync)
} }
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET)) if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET))
fe->uid = cpu_to_le32(-1); fe->uid = cpu_to_le32(UDF_INVALID_ID);
else else
fe->uid = cpu_to_le32(i_uid_read(inode)); fe->uid = cpu_to_le32(i_uid_read(inode));
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_FORGET)) if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_FORGET))
fe->gid = cpu_to_le32(-1); fe->gid = cpu_to_le32(UDF_INVALID_ID);
else else
fe->gid = cpu_to_le32(i_gid_read(inode)); fe->gid = cpu_to_le32(i_gid_read(inode));
......
This diff is collapsed.
...@@ -23,14 +23,13 @@ ...@@ -23,14 +23,13 @@
#define UDF_FLAG_NLS_MAP 9 #define UDF_FLAG_NLS_MAP 9
#define UDF_FLAG_UTF8 10 #define UDF_FLAG_UTF8 10
#define UDF_FLAG_UID_FORGET 11 /* save -1 for uid to disk */ #define UDF_FLAG_UID_FORGET 11 /* save -1 for uid to disk */
#define UDF_FLAG_UID_IGNORE 12 /* use sb uid instead of on disk uid */ #define UDF_FLAG_GID_FORGET 12
#define UDF_FLAG_GID_FORGET 13 #define UDF_FLAG_UID_SET 13
#define UDF_FLAG_GID_IGNORE 14 #define UDF_FLAG_GID_SET 14
#define UDF_FLAG_UID_SET 15 #define UDF_FLAG_SESSION_SET 15
#define UDF_FLAG_GID_SET 16 #define UDF_FLAG_LASTBLOCK_SET 16
#define UDF_FLAG_SESSION_SET 17 #define UDF_FLAG_BLOCKSIZE_SET 17
#define UDF_FLAG_LASTBLOCK_SET 18 #define UDF_FLAG_INCONSISTENT 18
#define UDF_FLAG_BLOCKSIZE_SET 19
#define UDF_PART_FLAG_UNALLOC_BITMAP 0x0001 #define UDF_PART_FLAG_UNALLOC_BITMAP 0x0001
#define UDF_PART_FLAG_UNALLOC_TABLE 0x0002 #define UDF_PART_FLAG_UNALLOC_TABLE 0x0002
......
...@@ -48,6 +48,8 @@ extern __printf(3, 4) void _udf_warn(struct super_block *sb, ...@@ -48,6 +48,8 @@ extern __printf(3, 4) void _udf_warn(struct super_block *sb,
#define UDF_EXTENT_LENGTH_MASK 0x3FFFFFFF #define UDF_EXTENT_LENGTH_MASK 0x3FFFFFFF
#define UDF_EXTENT_FLAG_MASK 0xC0000000 #define UDF_EXTENT_FLAG_MASK 0xC0000000
#define UDF_INVALID_ID ((uint32_t)-1)
#define UDF_NAME_PAD 4 #define UDF_NAME_PAD 4
#define UDF_NAME_LEN 254 #define UDF_NAME_LEN 254
#define UDF_NAME_LEN_CS0 255 #define UDF_NAME_LEN_CS0 255
......
...@@ -331,6 +331,12 @@ extern int fsnotify_add_event(struct fsnotify_group *group, ...@@ -331,6 +331,12 @@ extern int fsnotify_add_event(struct fsnotify_group *group,
struct fsnotify_event *event, struct fsnotify_event *event,
int (*merge)(struct list_head *, int (*merge)(struct list_head *,
struct fsnotify_event *)); struct fsnotify_event *));
/* Queue overflow event to a notification group */
static inline void fsnotify_queue_overflow(struct fsnotify_group *group)
{
fsnotify_add_event(group, group->overflow_event, NULL);
}
/* true if the group notification queue is empty */ /* true if the group notification queue is empty */
extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group); extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
/* return, but do not dequeue the first event on the notification queue */ /* return, but do not dequeue the first event on the notification queue */
......
...@@ -267,7 +267,6 @@ struct dqstats { ...@@ -267,7 +267,6 @@ struct dqstats {
struct percpu_counter counter[_DQST_DQSTAT_LAST]; struct percpu_counter counter[_DQST_DQSTAT_LAST];
}; };
extern struct dqstats *dqstats_pcpu;
extern struct dqstats dqstats; extern struct dqstats dqstats;
static inline void dqstats_inc(unsigned int type) static inline void dqstats_inc(unsigned int type)
......
...@@ -71,5 +71,13 @@ struct inotify_event { ...@@ -71,5 +71,13 @@ struct inotify_event {
#define IN_CLOEXEC O_CLOEXEC #define IN_CLOEXEC O_CLOEXEC
#define IN_NONBLOCK O_NONBLOCK #define IN_NONBLOCK O_NONBLOCK
/*
* ioctl numbers: inotify uses 'I' prefix for all ioctls,
* except historical FIONREAD, which is based on 'T'.
*
* INOTIFY_IOC_SETNEXTWD: set desired number of next created
* watch descriptor.
*/
#define INOTIFY_IOC_SETNEXTWD _IOW('I', 0, __s32)
#endif /* _UAPI_LINUX_INOTIFY_H */ #endif /* _UAPI_LINUX_INOTIFY_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment