mm/shmem: fix chattr fsflags support in tmpfs
ext[234] have always allowed unimplemented chattr flags to be set, but
other filesystems have tended to be stricter. Follow the stricter
approach for tmpfs: I don't want to have to explain why csu attributes
don't actually work, and we won't need to update the chattr(1) manpage;
and it's never wrong to start off strict, relaxing later if persuaded.
Allow only a (append only) i (immutable) A (no atime) and d (no dump).
Although lsattr showed 'A' inherited, the NOATIME behavior was not being
inherited: because nothing sync'ed FS_NOATIME_FL to S_NOATIME. Add
shmem_set_inode_flags() to sync the flags, using inode_set_flags() to
avoid that instant of lost immutablility during fileattr_set().
But that change switched generic/079 from passing to failing: because
FS_IMMUTABLE_FL and FS_APPEND_FL had been unconventionally included in the
INHERITED fsflags: remove them and generic/079 is back to passing.
Link: https://lkml.kernel.org/r/2961dcb0-ddf3-b9f0-3268-12a4ff996856@google.com
Fixes: e408e695f5
("mm/shmem: support FS_IOC_[SG]ETFLAGS in tmpfs")
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: "Theodore Ts'o" <tytso@mit.edu>
Cc: Radoslaw Burny <rburny@google.com>
Cc: "Darrick J. Wong" <djwong@kernel.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
1d8d14641f
commit
cb241339b9
|
@ -29,15 +29,10 @@ struct shmem_inode_info {
|
||||||
struct inode vfs_inode;
|
struct inode vfs_inode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SHMEM_FL_USER_VISIBLE FS_FL_USER_VISIBLE
|
#define SHMEM_FL_USER_VISIBLE FS_FL_USER_VISIBLE
|
||||||
#define SHMEM_FL_USER_MODIFIABLE FS_FL_USER_MODIFIABLE
|
#define SHMEM_FL_USER_MODIFIABLE \
|
||||||
#define SHMEM_FL_INHERITED FS_FL_USER_MODIFIABLE
|
(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL | FS_NOATIME_FL)
|
||||||
|
#define SHMEM_FL_INHERITED (FS_NODUMP_FL | FS_NOATIME_FL)
|
||||||
/* Flags that are appropriate for regular files (all but dir-specific ones). */
|
|
||||||
#define SHMEM_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
|
|
||||||
|
|
||||||
/* Flags that are appropriate for non-directories/regular files. */
|
|
||||||
#define SHMEM_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL)
|
|
||||||
|
|
||||||
struct shmem_sb_info {
|
struct shmem_sb_info {
|
||||||
unsigned long max_blocks; /* How many blocks are allowed */
|
unsigned long max_blocks; /* How many blocks are allowed */
|
||||||
|
|
54
mm/shmem.c
54
mm/shmem.c
|
@ -2281,16 +2281,34 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mask out flags that are inappropriate for the given type of inode. */
|
#ifdef CONFIG_TMPFS_XATTR
|
||||||
static unsigned shmem_mask_flags(umode_t mode, __u32 flags)
|
static int shmem_initxattrs(struct inode *, const struct xattr *, void *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* chattr's fsflags are unrelated to extended attributes,
|
||||||
|
* but tmpfs has chosen to enable them under the same config option.
|
||||||
|
*/
|
||||||
|
static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags)
|
||||||
{
|
{
|
||||||
if (S_ISDIR(mode))
|
unsigned int i_flags = 0;
|
||||||
return flags;
|
|
||||||
else if (S_ISREG(mode))
|
if (fsflags & FS_NOATIME_FL)
|
||||||
return flags & SHMEM_REG_FLMASK;
|
i_flags |= S_NOATIME;
|
||||||
else
|
if (fsflags & FS_APPEND_FL)
|
||||||
return flags & SHMEM_OTHER_FLMASK;
|
i_flags |= S_APPEND;
|
||||||
|
if (fsflags & FS_IMMUTABLE_FL)
|
||||||
|
i_flags |= S_IMMUTABLE;
|
||||||
|
/*
|
||||||
|
* But FS_NODUMP_FL does not require any action in i_flags.
|
||||||
|
*/
|
||||||
|
inode_set_flags(inode, i_flags, S_NOATIME | S_APPEND | S_IMMUTABLE);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#define shmem_initxattrs NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct inode *shmem_get_inode(struct super_block *sb, struct inode *dir,
|
static struct inode *shmem_get_inode(struct super_block *sb, struct inode *dir,
|
||||||
umode_t mode, dev_t dev, unsigned long flags)
|
umode_t mode, dev_t dev, unsigned long flags)
|
||||||
|
@ -2319,7 +2337,8 @@ static struct inode *shmem_get_inode(struct super_block *sb, struct inode *dir,
|
||||||
info->i_crtime = inode->i_mtime;
|
info->i_crtime = inode->i_mtime;
|
||||||
info->fsflags = (dir == NULL) ? 0 :
|
info->fsflags = (dir == NULL) ? 0 :
|
||||||
SHMEM_I(dir)->fsflags & SHMEM_FL_INHERITED;
|
SHMEM_I(dir)->fsflags & SHMEM_FL_INHERITED;
|
||||||
info->fsflags = shmem_mask_flags(mode, info->fsflags);
|
if (info->fsflags)
|
||||||
|
shmem_set_inode_flags(inode, info->fsflags);
|
||||||
INIT_LIST_HEAD(&info->shrinklist);
|
INIT_LIST_HEAD(&info->shrinklist);
|
||||||
INIT_LIST_HEAD(&info->swaplist);
|
INIT_LIST_HEAD(&info->swaplist);
|
||||||
simple_xattrs_init(&info->xattrs);
|
simple_xattrs_init(&info->xattrs);
|
||||||
|
@ -2468,12 +2487,6 @@ out_unacct_blocks:
|
||||||
static const struct inode_operations shmem_symlink_inode_operations;
|
static const struct inode_operations shmem_symlink_inode_operations;
|
||||||
static const struct inode_operations shmem_short_symlink_operations;
|
static const struct inode_operations shmem_short_symlink_operations;
|
||||||
|
|
||||||
#ifdef CONFIG_TMPFS_XATTR
|
|
||||||
static int shmem_initxattrs(struct inode *, const struct xattr *, void *);
|
|
||||||
#else
|
|
||||||
#define shmem_initxattrs NULL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
shmem_write_begin(struct file *file, struct address_space *mapping,
|
shmem_write_begin(struct file *file, struct address_space *mapping,
|
||||||
loff_t pos, unsigned len,
|
loff_t pos, unsigned len,
|
||||||
|
@ -3179,18 +3192,13 @@ static int shmem_fileattr_set(struct user_namespace *mnt_userns,
|
||||||
|
|
||||||
if (fileattr_has_fsx(fa))
|
if (fileattr_has_fsx(fa))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
if (fa->flags & ~SHMEM_FL_USER_MODIFIABLE)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
info->fsflags = (info->fsflags & ~SHMEM_FL_USER_MODIFIABLE) |
|
info->fsflags = (info->fsflags & ~SHMEM_FL_USER_MODIFIABLE) |
|
||||||
(fa->flags & SHMEM_FL_USER_MODIFIABLE);
|
(fa->flags & SHMEM_FL_USER_MODIFIABLE);
|
||||||
|
|
||||||
inode->i_flags &= ~(S_APPEND | S_IMMUTABLE | S_NOATIME);
|
shmem_set_inode_flags(inode, info->fsflags);
|
||||||
if (info->fsflags & FS_APPEND_FL)
|
|
||||||
inode->i_flags |= S_APPEND;
|
|
||||||
if (info->fsflags & FS_IMMUTABLE_FL)
|
|
||||||
inode->i_flags |= S_IMMUTABLE;
|
|
||||||
if (info->fsflags & FS_NOATIME_FL)
|
|
||||||
inode->i_flags |= S_NOATIME;
|
|
||||||
|
|
||||||
inode->i_ctime = current_time(inode);
|
inode->i_ctime = current_time(inode);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue