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));
......
...@@ -64,14 +64,13 @@ ...@@ -64,14 +64,13 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#define VDS_POS_PRIMARY_VOL_DESC 0 enum {
#define VDS_POS_UNALLOC_SPACE_DESC 1 VDS_POS_PRIMARY_VOL_DESC,
#define VDS_POS_LOGICAL_VOL_DESC 2 VDS_POS_UNALLOC_SPACE_DESC,
#define VDS_POS_PARTITION_DESC 3 VDS_POS_LOGICAL_VOL_DESC,
#define VDS_POS_IMP_USE_VOL_DESC 4 VDS_POS_IMP_USE_VOL_DESC,
#define VDS_POS_VOL_DESC_PTR 5 VDS_POS_LENGTH
#define VDS_POS_TERMINATING_DESC 6 };
#define VDS_POS_LENGTH 7
#define VSD_FIRST_SECTOR_OFFSET 32768 #define VSD_FIRST_SECTOR_OFFSET 32768
#define VSD_MAX_SECTOR_OFFSET 0x800000 #define VSD_MAX_SECTOR_OFFSET 0x800000
...@@ -223,10 +222,6 @@ struct udf_options { ...@@ -223,10 +222,6 @@ struct udf_options {
unsigned int session; unsigned int session;
unsigned int lastblock; unsigned int lastblock;
unsigned int anchor; unsigned int anchor;
unsigned int volume;
unsigned short partition;
unsigned int fileset;
unsigned int rootdir;
unsigned int flags; unsigned int flags;
umode_t umask; umode_t umask;
kgid_t gid; kgid_t gid;
...@@ -349,12 +344,8 @@ static int udf_show_options(struct seq_file *seq, struct dentry *root) ...@@ -349,12 +344,8 @@ static int udf_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",shortad"); seq_puts(seq, ",shortad");
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_FORGET)) if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_FORGET))
seq_puts(seq, ",uid=forget"); seq_puts(seq, ",uid=forget");
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_IGNORE))
seq_puts(seq, ",uid=ignore");
if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_FORGET)) if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_FORGET))
seq_puts(seq, ",gid=forget"); seq_puts(seq, ",gid=forget");
if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_IGNORE))
seq_puts(seq, ",gid=ignore");
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_SET)) if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_SET))
seq_printf(seq, ",uid=%u", from_kuid(&init_user_ns, sbi->s_uid)); seq_printf(seq, ",uid=%u", from_kuid(&init_user_ns, sbi->s_uid));
if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_SET)) if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_SET))
...@@ -371,10 +362,6 @@ static int udf_show_options(struct seq_file *seq, struct dentry *root) ...@@ -371,10 +362,6 @@ static int udf_show_options(struct seq_file *seq, struct dentry *root)
seq_printf(seq, ",lastblock=%u", sbi->s_last_block); seq_printf(seq, ",lastblock=%u", sbi->s_last_block);
if (sbi->s_anchor != 0) if (sbi->s_anchor != 0)
seq_printf(seq, ",anchor=%u", sbi->s_anchor); seq_printf(seq, ",anchor=%u", sbi->s_anchor);
/*
* volume, partition, fileset and rootdir seem to be ignored
* currently
*/
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
seq_puts(seq, ",utf8"); seq_puts(seq, ",utf8");
if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP) && sbi->s_nls_map) if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP) && sbi->s_nls_map)
...@@ -487,14 +474,9 @@ static int udf_parse_options(char *options, struct udf_options *uopt, ...@@ -487,14 +474,9 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
int option; int option;
uopt->novrs = 0; uopt->novrs = 0;
uopt->partition = 0xFFFF;
uopt->session = 0xFFFFFFFF; uopt->session = 0xFFFFFFFF;
uopt->lastblock = 0; uopt->lastblock = 0;
uopt->anchor = 0; uopt->anchor = 0;
uopt->volume = 0xFFFFFFFF;
uopt->rootdir = 0xFFFFFFFF;
uopt->fileset = 0xFFFFFFFF;
uopt->nls_map = NULL;
if (!options) if (!options)
return 1; return 1;
...@@ -582,42 +564,30 @@ static int udf_parse_options(char *options, struct udf_options *uopt, ...@@ -582,42 +564,30 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
uopt->anchor = option; uopt->anchor = option;
break; break;
case Opt_volume: case Opt_volume:
if (match_int(args, &option))
return 0;
uopt->volume = option;
break;
case Opt_partition: case Opt_partition:
if (match_int(args, &option))
return 0;
uopt->partition = option;
break;
case Opt_fileset: case Opt_fileset:
if (match_int(args, &option))
return 0;
uopt->fileset = option;
break;
case Opt_rootdir: case Opt_rootdir:
if (match_int(args, &option)) /* Ignored (never implemented properly) */
return 0;
uopt->rootdir = option;
break; break;
case Opt_utf8: case Opt_utf8:
uopt->flags |= (1 << UDF_FLAG_UTF8); uopt->flags |= (1 << UDF_FLAG_UTF8);
break; break;
#ifdef CONFIG_UDF_NLS #ifdef CONFIG_UDF_NLS
case Opt_iocharset: case Opt_iocharset:
uopt->nls_map = load_nls(args[0].from); if (!remount) {
uopt->flags |= (1 << UDF_FLAG_NLS_MAP); if (uopt->nls_map)
unload_nls(uopt->nls_map);
uopt->nls_map = load_nls(args[0].from);
uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
}
break; break;
#endif #endif
case Opt_uignore:
uopt->flags |= (1 << UDF_FLAG_UID_IGNORE);
break;
case Opt_uforget: case Opt_uforget:
uopt->flags |= (1 << UDF_FLAG_UID_FORGET); uopt->flags |= (1 << UDF_FLAG_UID_FORGET);
break; break;
case Opt_uignore:
case Opt_gignore: case Opt_gignore:
uopt->flags |= (1 << UDF_FLAG_GID_IGNORE); /* These options are superseeded by uid=<number> */
break; break;
case Opt_gforget: case Opt_gforget:
uopt->flags |= (1 << UDF_FLAG_GID_FORGET); uopt->flags |= (1 << UDF_FLAG_GID_FORGET);
...@@ -660,6 +630,7 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) ...@@ -660,6 +630,7 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
uopt.umask = sbi->s_umask; uopt.umask = sbi->s_umask;
uopt.fmode = sbi->s_fmode; uopt.fmode = sbi->s_fmode;
uopt.dmode = sbi->s_dmode; uopt.dmode = sbi->s_dmode;
uopt.nls_map = NULL;
if (!udf_parse_options(options, &uopt, true)) if (!udf_parse_options(options, &uopt, true))
return -EINVAL; return -EINVAL;
...@@ -1592,6 +1563,60 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_ ...@@ -1592,6 +1563,60 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
sbi->s_lvid_bh = NULL; sbi->s_lvid_bh = NULL;
} }
/*
* Step for reallocation of table of partition descriptor sequence numbers.
* Must be power of 2.
*/
#define PART_DESC_ALLOC_STEP 32
struct desc_seq_scan_data {
struct udf_vds_record vds[VDS_POS_LENGTH];
unsigned int size_part_descs;
struct udf_vds_record *part_descs_loc;
};
static struct udf_vds_record *handle_partition_descriptor(
struct buffer_head *bh,
struct desc_seq_scan_data *data)
{
struct partitionDesc *desc = (struct partitionDesc *)bh->b_data;
int partnum;
partnum = le16_to_cpu(desc->partitionNumber);
if (partnum >= data->size_part_descs) {
struct udf_vds_record *new_loc;
unsigned int new_size = ALIGN(partnum, PART_DESC_ALLOC_STEP);
new_loc = kzalloc(sizeof(*new_loc) * new_size, GFP_KERNEL);
if (!new_loc)
return ERR_PTR(-ENOMEM);
memcpy(new_loc, data->part_descs_loc,
data->size_part_descs * sizeof(*new_loc));
kfree(data->part_descs_loc);
data->part_descs_loc = new_loc;
data->size_part_descs = new_size;
}
return &(data->part_descs_loc[partnum]);
}
static struct udf_vds_record *get_volume_descriptor_record(uint16_t ident,
struct buffer_head *bh, struct desc_seq_scan_data *data)
{
switch (ident) {
case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
return &(data->vds[VDS_POS_PRIMARY_VOL_DESC]);
case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
return &(data->vds[VDS_POS_IMP_USE_VOL_DESC]);
case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
return &(data->vds[VDS_POS_LOGICAL_VOL_DESC]);
case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
return &(data->vds[VDS_POS_UNALLOC_SPACE_DESC]);
case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
return handle_partition_descriptor(bh, data);
}
return NULL;
}
/* /*
* Process a main/reserve volume descriptor sequence. * Process a main/reserve volume descriptor sequence.
...@@ -1608,18 +1633,23 @@ static noinline int udf_process_sequence( ...@@ -1608,18 +1633,23 @@ static noinline int udf_process_sequence(
struct kernel_lb_addr *fileset) struct kernel_lb_addr *fileset)
{ {
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct udf_vds_record vds[VDS_POS_LENGTH];
struct udf_vds_record *curr; struct udf_vds_record *curr;
struct generic_desc *gd; struct generic_desc *gd;
struct volDescPtr *vdp; struct volDescPtr *vdp;
bool done = false; bool done = false;
uint32_t vdsn; uint32_t vdsn;
uint16_t ident; uint16_t ident;
long next_s = 0, next_e = 0;
int ret; int ret;
unsigned int indirections = 0; unsigned int indirections = 0;
struct desc_seq_scan_data data;
memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); unsigned int i;
memset(data.vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
data.size_part_descs = PART_DESC_ALLOC_STEP;
data.part_descs_loc = kzalloc(sizeof(*data.part_descs_loc) *
data.size_part_descs, GFP_KERNEL);
if (!data.part_descs_loc)
return -ENOMEM;
/* /*
* Read the main descriptor sequence and find which descriptors * Read the main descriptor sequence and find which descriptors
...@@ -1628,79 +1658,51 @@ static noinline int udf_process_sequence( ...@@ -1628,79 +1658,51 @@ static noinline int udf_process_sequence(
for (; (!done && block <= lastblock); block++) { for (; (!done && block <= lastblock); block++) {
bh = udf_read_tagged(sb, block, block, &ident); bh = udf_read_tagged(sb, block, block, &ident);
if (!bh) { if (!bh)
udf_err(sb, break;
"Block %llu of volume descriptor sequence is corrupted or we could not read it\n",
(unsigned long long)block);
return -EAGAIN;
}
/* Process each descriptor (ISO 13346 3/8.3-8.4) */ /* Process each descriptor (ISO 13346 3/8.3-8.4) */
gd = (struct generic_desc *)bh->b_data; gd = (struct generic_desc *)bh->b_data;
vdsn = le32_to_cpu(gd->volDescSeqNum); vdsn = le32_to_cpu(gd->volDescSeqNum);
switch (ident) { switch (ident) {
case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
curr = &vds[VDS_POS_PRIMARY_VOL_DESC];
if (vdsn >= curr->volDescSeqNum) {
curr->volDescSeqNum = vdsn;
curr->block = block;
}
break;
case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */ case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */
curr = &vds[VDS_POS_VOL_DESC_PTR]; if (++indirections > UDF_MAX_TD_NESTING) {
if (vdsn >= curr->volDescSeqNum) { udf_err(sb, "too many Volume Descriptor "
curr->volDescSeqNum = vdsn; "Pointers (max %u supported)\n",
curr->block = block; UDF_MAX_TD_NESTING);
brelse(bh);
vdp = (struct volDescPtr *)bh->b_data; return -EIO;
next_s = le32_to_cpu(
vdp->nextVolDescSeqExt.extLocation);
next_e = le32_to_cpu(
vdp->nextVolDescSeqExt.extLength);
next_e = next_e >> sb->s_blocksize_bits;
next_e += next_s;
} }
vdp = (struct volDescPtr *)bh->b_data;
block = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation);
lastblock = le32_to_cpu(
vdp->nextVolDescSeqExt.extLength) >>
sb->s_blocksize_bits;
lastblock += block - 1;
/* For loop is going to increment 'block' again */
block--;
break; break;
case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */ case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
curr = &vds[VDS_POS_IMP_USE_VOL_DESC];
if (vdsn >= curr->volDescSeqNum) {
curr->volDescSeqNum = vdsn;
curr->block = block;
}
break;
case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
curr = &vds[VDS_POS_PARTITION_DESC];
if (!curr->block)
curr->block = block;
break;
case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */ case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
curr = &vds[VDS_POS_LOGICAL_VOL_DESC];
if (vdsn >= curr->volDescSeqNum) {
curr->volDescSeqNum = vdsn;
curr->block = block;
}
break;
case TAG_IDENT_USD: /* ISO 13346 3/10.8 */ case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
curr = &vds[VDS_POS_UNALLOC_SPACE_DESC]; case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
curr = get_volume_descriptor_record(ident, bh, &data);
if (IS_ERR(curr)) {
brelse(bh);
return PTR_ERR(curr);
}
/* Descriptor we don't care about? */
if (!curr)
break;
if (vdsn >= curr->volDescSeqNum) { if (vdsn >= curr->volDescSeqNum) {
curr->volDescSeqNum = vdsn; curr->volDescSeqNum = vdsn;
curr->block = block; curr->block = block;
} }
break; break;
case TAG_IDENT_TD: /* ISO 13346 3/10.9 */ case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
if (++indirections > UDF_MAX_TD_NESTING) { done = true;
udf_err(sb, "too many TDs (max %u supported)\n", UDF_MAX_TD_NESTING);
brelse(bh);
return -EIO;
}
vds[VDS_POS_TERMINATING_DESC].block = block;
if (next_e) {
block = next_s;
lastblock = next_e;
next_s = next_e = 0;
} else
done = true;
break; break;
} }
brelse(bh); brelse(bh);
...@@ -1709,31 +1711,27 @@ static noinline int udf_process_sequence( ...@@ -1709,31 +1711,27 @@ static noinline int udf_process_sequence(
* Now read interesting descriptors again and process them * Now read interesting descriptors again and process them
* in a suitable order * in a suitable order
*/ */
if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) { if (!data.vds[VDS_POS_PRIMARY_VOL_DESC].block) {
udf_err(sb, "Primary Volume Descriptor not found!\n"); udf_err(sb, "Primary Volume Descriptor not found!\n");
return -EAGAIN; return -EAGAIN;
} }
ret = udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block); ret = udf_load_pvoldesc(sb, data.vds[VDS_POS_PRIMARY_VOL_DESC].block);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (vds[VDS_POS_LOGICAL_VOL_DESC].block) { if (data.vds[VDS_POS_LOGICAL_VOL_DESC].block) {
ret = udf_load_logicalvol(sb, ret = udf_load_logicalvol(sb,
vds[VDS_POS_LOGICAL_VOL_DESC].block, data.vds[VDS_POS_LOGICAL_VOL_DESC].block,
fileset); fileset);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
if (vds[VDS_POS_PARTITION_DESC].block) { /* Now handle prevailing Partition Descriptors */
/* for (i = 0; i < data.size_part_descs; i++) {
* We rescan the whole descriptor sequence to find if (data.part_descs_loc[i].block) {
* partition descriptor blocks and process them. ret = udf_load_partdesc(sb,
*/ data.part_descs_loc[i].block);
for (block = vds[VDS_POS_PARTITION_DESC].block;
block < vds[VDS_POS_TERMINATING_DESC].block;
block++) {
ret = udf_load_partdesc(sb, block);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
...@@ -1760,13 +1758,13 @@ static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh, ...@@ -1760,13 +1758,13 @@ static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh,
main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation); main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation);
main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength); main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength);
main_e = main_e >> sb->s_blocksize_bits; main_e = main_e >> sb->s_blocksize_bits;
main_e += main_s; main_e += main_s - 1;
/* Locate the reserve sequence */ /* Locate the reserve sequence */
reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation); reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation);
reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength); reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength);
reserve_e = reserve_e >> sb->s_blocksize_bits; reserve_e = reserve_e >> sb->s_blocksize_bits;
reserve_e += reserve_s; reserve_e += reserve_s - 1;
/* Process the main & reserve sequences */ /* Process the main & reserve sequences */
/* responsible for finding the PartitionDesc(s) */ /* responsible for finding the PartitionDesc(s) */
...@@ -1994,7 +1992,10 @@ static void udf_open_lvid(struct super_block *sb) ...@@ -1994,7 +1992,10 @@ static void udf_open_lvid(struct super_block *sb)
lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
ktime_get_real_ts(&ts); ktime_get_real_ts(&ts);
udf_time_to_disk_stamp(&lvid->recordingDateAndTime, ts); udf_time_to_disk_stamp(&lvid->recordingDateAndTime, ts);
lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN); if (le32_to_cpu(lvid->integrityType) == LVID_INTEGRITY_TYPE_CLOSE)
lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN);
else
UDF_SET_FLAG(sb, UDF_FLAG_INCONSISTENT);
lvid->descTag.descCRC = cpu_to_le16( lvid->descTag.descCRC = cpu_to_le16(
crc_itu_t(0, (char *)lvid + sizeof(struct tag), crc_itu_t(0, (char *)lvid + sizeof(struct tag),
...@@ -2034,7 +2035,8 @@ static void udf_close_lvid(struct super_block *sb) ...@@ -2034,7 +2035,8 @@ static void udf_close_lvid(struct super_block *sb)
lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev); lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev);
if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev)) if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev))
lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev); lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev);
lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); if (!UDF_QUERY_FLAG(sb, UDF_FLAG_INCONSISTENT))
lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE);
lvid->descTag.descCRC = cpu_to_le16( lvid->descTag.descCRC = cpu_to_le16(
crc_itu_t(0, (char *)lvid + sizeof(struct tag), crc_itu_t(0, (char *)lvid + sizeof(struct tag),
...@@ -2091,11 +2093,13 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2091,11 +2093,13 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
bool lvid_open = false; bool lvid_open = false;
uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT); uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT);
uopt.uid = INVALID_UID; /* By default we'll use overflow[ug]id when UDF inode [ug]id == -1 */
uopt.gid = INVALID_GID; uopt.uid = make_kuid(current_user_ns(), overflowuid);
uopt.gid = make_kgid(current_user_ns(), overflowgid);
uopt.umask = 0; uopt.umask = 0;
uopt.fmode = UDF_INVALID_MODE; uopt.fmode = UDF_INVALID_MODE;
uopt.dmode = UDF_INVALID_MODE; uopt.dmode = UDF_INVALID_MODE;
uopt.nls_map = NULL;
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi) if (!sbi)
...@@ -2276,8 +2280,8 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2276,8 +2280,8 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
iput(sbi->s_vat_inode); iput(sbi->s_vat_inode);
parse_options_failure: parse_options_failure:
#ifdef CONFIG_UDF_NLS #ifdef CONFIG_UDF_NLS
if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) if (uopt.nls_map)
unload_nls(sbi->s_nls_map); unload_nls(uopt.nls_map);
#endif #endif
if (lvid_open) if (lvid_open)
udf_close_lvid(sb); udf_close_lvid(sb);
......
...@@ -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