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
This commit is contained in:
Linus Torvalds 2018-04-05 19:17:50 -07:00
commit be88751f32
18 changed files with 239 additions and 178 deletions

View File

@ -36,18 +36,14 @@ The following mount options are supported:
iocharset= Set the NLS character set
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.
They will also accept the string "ignore" and "forget". For files on the disk
that are owned by nobody ( -1 ), they will instead look as if they are owned
by the default ID. The ignore option causes the default ID to override all
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.
decimal numeric value and all inodes on that mount will then appear as
belonging to that uid and gid. Mount options also accept the string "forget".
The forget option causes all IDs to be written to disk as -1 which is a way
of UDF standard to indicate that IDs are not supported for these files .
For typical desktop use of removable media, you should set the ID to that
of the interactively logged on user, and also specify both the forget and
ignore options. This way the interactive user will always see the files
on the disk as belonging to him.
For typical desktop use of removable media, you should set the ID to that of
the interactively logged on user, and also specify the forget option. This way
the interactive user will always see the files on the disk as belonging to him.
The remaining are for debugging and disaster recovery:
@ -57,16 +53,8 @@ The following expect a offset from 0.
session= Set the CDROM session (default= last session)
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/
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.
-------------------------------------------------------------------------------

View File

@ -827,7 +827,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
unsigned long logic_sb_block;
unsigned long offset = 0;
unsigned long def_mount_opts;
long ret = -EINVAL;
long ret = -ENOMEM;
int blocksize = BLOCK_SIZE;
int db_count;
int i, j;
@ -835,7 +835,6 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
int err;
struct ext2_mount_options opts;
err = -ENOMEM;
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
goto failed;
@ -851,6 +850,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
sbi->s_daxdev = dax_dev;
spin_lock_init(&sbi->s_lock);
ret = -EINVAL;
/*
* See what the current blocksize for the device is, and

View File

@ -139,23 +139,32 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
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)
{
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)) {
struct fanotify_perm_event_info *pevent;
pevent = kmem_cache_alloc(fanotify_perm_event_cachep,
GFP_KERNEL);
pevent = kmem_cache_alloc(fanotify_perm_event_cachep, gfp);
if (!pevent)
return NULL;
event = &pevent->fae;
pevent->response = 0;
goto init;
}
event = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL);
event = kmem_cache_alloc(fanotify_event_cachep, gfp);
if (!event)
return NULL;
init: __maybe_unused
@ -210,10 +219,17 @@ static int fanotify_handle_event(struct fsnotify_group *group,
return 0;
}
event = fanotify_alloc_event(inode, mask, data);
event = fanotify_alloc_event(group, inode, mask, data);
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;
}
fsn_event = &event->fse;
ret = fsnotify_add_event(group, fsn_event, fanotify_merge);

View File

@ -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);
}
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);

View File

@ -757,7 +757,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
group->fanotify_data.user = user;
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)) {
fd = -ENOMEM;
goto out_destroy_group;

View File

@ -99,8 +99,14 @@ int inotify_handle_event(struct fsnotify_group *group,
fsn_mark);
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;
}
fsn_event = &event->fse;
fsnotify_init_event(fsn_event, inode, mask);

View File

@ -307,6 +307,20 @@ static long inotify_ioctl(struct file *file, unsigned int cmd,
spin_unlock(&group->notification_lock);
ret = put_user(send_len, (int __user *) p);
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;

View File

@ -111,7 +111,8 @@ int fsnotify_add_event(struct fsnotify_group *group,
return 2;
}
if (group->q_len >= group->max_events) {
if (event == group->overflow_event ||
group->q_len >= group->max_events) {
ret = 2;
/* Queue overflow event only if it isn't already queued */
if (!list_empty(&group->overflow_event->list)) {

View File

@ -1916,7 +1916,7 @@ struct reiserfs_de_head {
/* empty directory contains two entries "." and ".." and their headers */
#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 */
#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3)

View File

@ -257,12 +257,22 @@ const struct file_operations udf_file_operations = {
static int udf_setattr(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = d_inode(dentry);
struct super_block *sb = inode->i_sb;
int error;
error = setattr_prepare(dentry, attr);
if (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) &&
attr->ia_size != i_size_read(inode)) {
error = udf_setsize(inode, attr->ia_size);

View File

@ -104,6 +104,10 @@ struct inode *udf_new_inode(struct inode *dir, umode_t 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.partitionReferenceNum =

View File

@ -1275,6 +1275,7 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode)
unsigned int indirections = 0;
int bs = inode->i_sb->s_blocksize;
int ret = -EIO;
uint32_t uid, gid;
reread:
if (iloc->partitionReferenceNum >= sbi->s_partitions) {
@ -1400,17 +1401,19 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode)
ret = -EIO;
read_lock(&sbi->s_cred_lock);
i_uid_write(inode, le32_to_cpu(fe->uid));
if (!uid_valid(inode->i_uid) ||
UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_IGNORE) ||
uid = le32_to_cpu(fe->uid);
if (uid == UDF_INVALID_ID ||
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));
if (!gid_valid(inode->i_gid) ||
UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_IGNORE) ||
gid = le32_to_cpu(fe->gid);
if (gid == UDF_INVALID_ID ||
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 &&
sbi->s_fmode != UDF_INVALID_MODE)
@ -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))
fe->uid = cpu_to_le32(-1);
fe->uid = cpu_to_le32(UDF_INVALID_ID);
else
fe->uid = cpu_to_le32(i_uid_read(inode));
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
fe->gid = cpu_to_le32(i_gid_read(inode));

View File

@ -64,14 +64,13 @@
#include <linux/init.h>
#include <linux/uaccess.h>
#define VDS_POS_PRIMARY_VOL_DESC 0
#define VDS_POS_UNALLOC_SPACE_DESC 1
#define VDS_POS_LOGICAL_VOL_DESC 2
#define VDS_POS_PARTITION_DESC 3
#define VDS_POS_IMP_USE_VOL_DESC 4
#define VDS_POS_VOL_DESC_PTR 5
#define VDS_POS_TERMINATING_DESC 6
#define VDS_POS_LENGTH 7
enum {
VDS_POS_PRIMARY_VOL_DESC,
VDS_POS_UNALLOC_SPACE_DESC,
VDS_POS_LOGICAL_VOL_DESC,
VDS_POS_IMP_USE_VOL_DESC,
VDS_POS_LENGTH
};
#define VSD_FIRST_SECTOR_OFFSET 32768
#define VSD_MAX_SECTOR_OFFSET 0x800000
@ -223,10 +222,6 @@ struct udf_options {
unsigned int session;
unsigned int lastblock;
unsigned int anchor;
unsigned int volume;
unsigned short partition;
unsigned int fileset;
unsigned int rootdir;
unsigned int flags;
umode_t umask;
kgid_t gid;
@ -349,12 +344,8 @@ static int udf_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",shortad");
if (UDF_QUERY_FLAG(sb, UDF_FLAG_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))
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))
seq_printf(seq, ",uid=%u", from_kuid(&init_user_ns, sbi->s_uid));
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)
seq_printf(seq, ",lastblock=%u", sbi->s_last_block);
if (sbi->s_anchor != 0)
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))
seq_puts(seq, ",utf8");
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,
int option;
uopt->novrs = 0;
uopt->partition = 0xFFFF;
uopt->session = 0xFFFFFFFF;
uopt->lastblock = 0;
uopt->anchor = 0;
uopt->volume = 0xFFFFFFFF;
uopt->rootdir = 0xFFFFFFFF;
uopt->fileset = 0xFFFFFFFF;
uopt->nls_map = NULL;
if (!options)
return 1;
@ -582,42 +564,30 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
uopt->anchor = option;
break;
case Opt_volume:
if (match_int(args, &option))
return 0;
uopt->volume = option;
break;
case Opt_partition:
if (match_int(args, &option))
return 0;
uopt->partition = option;
break;
case Opt_fileset:
if (match_int(args, &option))
return 0;
uopt->fileset = option;
break;
case Opt_rootdir:
if (match_int(args, &option))
return 0;
uopt->rootdir = option;
/* Ignored (never implemented properly) */
break;
case Opt_utf8:
uopt->flags |= (1 << UDF_FLAG_UTF8);
break;
#ifdef CONFIG_UDF_NLS
case Opt_iocharset:
uopt->nls_map = load_nls(args[0].from);
uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
if (!remount) {
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;
#endif
case Opt_uignore:
uopt->flags |= (1 << UDF_FLAG_UID_IGNORE);
break;
case Opt_uforget:
uopt->flags |= (1 << UDF_FLAG_UID_FORGET);
break;
case Opt_uignore:
case Opt_gignore:
uopt->flags |= (1 << UDF_FLAG_GID_IGNORE);
/* These options are superseeded by uid=<number> */
break;
case Opt_gforget:
uopt->flags |= (1 << UDF_FLAG_GID_FORGET);
@ -660,6 +630,7 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
uopt.umask = sbi->s_umask;
uopt.fmode = sbi->s_fmode;
uopt.dmode = sbi->s_dmode;
uopt.nls_map = NULL;
if (!udf_parse_options(options, &uopt, true))
return -EINVAL;
@ -1592,6 +1563,60 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
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.
@ -1608,18 +1633,23 @@ static noinline int udf_process_sequence(
struct kernel_lb_addr *fileset)
{
struct buffer_head *bh = NULL;
struct udf_vds_record vds[VDS_POS_LENGTH];
struct udf_vds_record *curr;
struct generic_desc *gd;
struct volDescPtr *vdp;
bool done = false;
uint32_t vdsn;
uint16_t ident;
long next_s = 0, next_e = 0;
int ret;
unsigned int indirections = 0;
struct desc_seq_scan_data data;
unsigned int i;
memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
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
@ -1628,79 +1658,51 @@ static noinline int udf_process_sequence(
for (; (!done && block <= lastblock); block++) {
bh = udf_read_tagged(sb, block, block, &ident);
if (!bh) {
udf_err(sb,
"Block %llu of volume descriptor sequence is corrupted or we could not read it\n",
(unsigned long long)block);
return -EAGAIN;
}
if (!bh)
break;
/* Process each descriptor (ISO 13346 3/8.3-8.4) */
gd = (struct generic_desc *)bh->b_data;
vdsn = le32_to_cpu(gd->volDescSeqNum);
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 */
curr = &vds[VDS_POS_VOL_DESC_PTR];
if (vdsn >= curr->volDescSeqNum) {
curr->volDescSeqNum = vdsn;
curr->block = block;
if (++indirections > UDF_MAX_TD_NESTING) {
udf_err(sb, "too many Volume Descriptor "
"Pointers (max %u supported)\n",
UDF_MAX_TD_NESTING);
brelse(bh);
return -EIO;
}
vdp = (struct volDescPtr *)bh->b_data;
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;
case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
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 */
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 */
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) {
curr->volDescSeqNum = vdsn;
curr->block = block;
}
break;
case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
if (++indirections > UDF_MAX_TD_NESTING) {
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;
done = true;
break;
}
brelse(bh);
@ -1709,31 +1711,27 @@ static noinline int udf_process_sequence(
* Now read interesting descriptors again and process them
* 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");
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)
return ret;
if (vds[VDS_POS_LOGICAL_VOL_DESC].block) {
if (data.vds[VDS_POS_LOGICAL_VOL_DESC].block) {
ret = udf_load_logicalvol(sb,
vds[VDS_POS_LOGICAL_VOL_DESC].block,
fileset);
data.vds[VDS_POS_LOGICAL_VOL_DESC].block,
fileset);
if (ret < 0)
return ret;
}
if (vds[VDS_POS_PARTITION_DESC].block) {
/*
* We rescan the whole descriptor sequence to find
* partition descriptor blocks and process them.
*/
for (block = vds[VDS_POS_PARTITION_DESC].block;
block < vds[VDS_POS_TERMINATING_DESC].block;
block++) {
ret = udf_load_partdesc(sb, block);
/* Now handle prevailing Partition Descriptors */
for (i = 0; i < data.size_part_descs; i++) {
if (data.part_descs_loc[i].block) {
ret = udf_load_partdesc(sb,
data.part_descs_loc[i].block);
if (ret < 0)
return ret;
}
@ -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_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength);
main_e = main_e >> sb->s_blocksize_bits;
main_e += main_s;
main_e += main_s - 1;
/* Locate the reserve sequence */
reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation);
reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength);
reserve_e = reserve_e >> sb->s_blocksize_bits;
reserve_e += reserve_s;
reserve_e += reserve_s - 1;
/* Process the main & reserve sequences */
/* responsible for finding the PartitionDesc(s) */
@ -1994,7 +1992,10 @@ static void udf_open_lvid(struct super_block *sb)
lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
ktime_get_real_ts(&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(
crc_itu_t(0, (char *)lvid + sizeof(struct tag),
@ -2034,7 +2035,8 @@ static void udf_close_lvid(struct super_block *sb)
lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev);
if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev))
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(
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)
bool lvid_open = false;
uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT);
uopt.uid = INVALID_UID;
uopt.gid = INVALID_GID;
/* By default we'll use overflow[ug]id when UDF inode [ug]id == -1 */
uopt.uid = make_kuid(current_user_ns(), overflowuid);
uopt.gid = make_kgid(current_user_ns(), overflowgid);
uopt.umask = 0;
uopt.fmode = UDF_INVALID_MODE;
uopt.dmode = UDF_INVALID_MODE;
uopt.nls_map = NULL;
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
@ -2276,8 +2280,8 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
iput(sbi->s_vat_inode);
parse_options_failure:
#ifdef CONFIG_UDF_NLS
if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
unload_nls(sbi->s_nls_map);
if (uopt.nls_map)
unload_nls(uopt.nls_map);
#endif
if (lvid_open)
udf_close_lvid(sb);

View File

@ -23,14 +23,13 @@
#define UDF_FLAG_NLS_MAP 9
#define UDF_FLAG_UTF8 10
#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 13
#define UDF_FLAG_GID_IGNORE 14
#define UDF_FLAG_UID_SET 15
#define UDF_FLAG_GID_SET 16
#define UDF_FLAG_SESSION_SET 17
#define UDF_FLAG_LASTBLOCK_SET 18
#define UDF_FLAG_BLOCKSIZE_SET 19
#define UDF_FLAG_GID_FORGET 12
#define UDF_FLAG_UID_SET 13
#define UDF_FLAG_GID_SET 14
#define UDF_FLAG_SESSION_SET 15
#define UDF_FLAG_LASTBLOCK_SET 16
#define UDF_FLAG_BLOCKSIZE_SET 17
#define UDF_FLAG_INCONSISTENT 18
#define UDF_PART_FLAG_UNALLOC_BITMAP 0x0001
#define UDF_PART_FLAG_UNALLOC_TABLE 0x0002

View File

@ -48,6 +48,8 @@ extern __printf(3, 4) void _udf_warn(struct super_block *sb,
#define UDF_EXTENT_LENGTH_MASK 0x3FFFFFFF
#define UDF_EXTENT_FLAG_MASK 0xC0000000
#define UDF_INVALID_ID ((uint32_t)-1)
#define UDF_NAME_PAD 4
#define UDF_NAME_LEN 254
#define UDF_NAME_LEN_CS0 255

View File

@ -331,6 +331,12 @@ extern int fsnotify_add_event(struct fsnotify_group *group,
struct fsnotify_event *event,
int (*merge)(struct list_head *,
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 */
extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
/* return, but do not dequeue the first event on the notification queue */

View File

@ -267,7 +267,6 @@ struct dqstats {
struct percpu_counter counter[_DQST_DQSTAT_LAST];
};
extern struct dqstats *dqstats_pcpu;
extern struct dqstats dqstats;
static inline void dqstats_inc(unsigned int type)

View File

@ -71,5 +71,13 @@ struct inotify_event {
#define IN_CLOEXEC O_CLOEXEC
#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 */