Skip to content

Commit cb24133

Browse files
Hugh Dickinsakpm00
authored andcommitted
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: e408e69 ("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>
1 parent 1d8d146 commit cb24133

2 files changed

Lines changed: 35 additions & 32 deletions

File tree

include/linux/shmem_fs.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,10 @@ struct shmem_inode_info {
2929
struct inode vfs_inode;
3030
};
3131

32-
#define SHMEM_FL_USER_VISIBLE FS_FL_USER_VISIBLE
33-
#define SHMEM_FL_USER_MODIFIABLE FS_FL_USER_MODIFIABLE
34-
#define SHMEM_FL_INHERITED FS_FL_USER_MODIFIABLE
35-
36-
/* Flags that are appropriate for regular files (all but dir-specific ones). */
37-
#define SHMEM_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
38-
39-
/* Flags that are appropriate for non-directories/regular files. */
40-
#define SHMEM_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL)
32+
#define SHMEM_FL_USER_VISIBLE FS_FL_USER_VISIBLE
33+
#define SHMEM_FL_USER_MODIFIABLE \
34+
(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL | FS_NOATIME_FL)
35+
#define SHMEM_FL_INHERITED (FS_NODUMP_FL | FS_NOATIME_FL)
4136

4237
struct shmem_sb_info {
4338
unsigned long max_blocks; /* How many blocks are allowed */

mm/shmem.c

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2281,16 +2281,34 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
22812281
return 0;
22822282
}
22832283

2284-
/* Mask out flags that are inappropriate for the given type of inode. */
2285-
static unsigned shmem_mask_flags(umode_t mode, __u32 flags)
2284+
#ifdef CONFIG_TMPFS_XATTR
2285+
static int shmem_initxattrs(struct inode *, const struct xattr *, void *);
2286+
2287+
/*
2288+
* chattr's fsflags are unrelated to extended attributes,
2289+
* but tmpfs has chosen to enable them under the same config option.
2290+
*/
2291+
static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags)
2292+
{
2293+
unsigned int i_flags = 0;
2294+
2295+
if (fsflags & FS_NOATIME_FL)
2296+
i_flags |= S_NOATIME;
2297+
if (fsflags & FS_APPEND_FL)
2298+
i_flags |= S_APPEND;
2299+
if (fsflags & FS_IMMUTABLE_FL)
2300+
i_flags |= S_IMMUTABLE;
2301+
/*
2302+
* But FS_NODUMP_FL does not require any action in i_flags.
2303+
*/
2304+
inode_set_flags(inode, i_flags, S_NOATIME | S_APPEND | S_IMMUTABLE);
2305+
}
2306+
#else
2307+
static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags)
22862308
{
2287-
if (S_ISDIR(mode))
2288-
return flags;
2289-
else if (S_ISREG(mode))
2290-
return flags & SHMEM_REG_FLMASK;
2291-
else
2292-
return flags & SHMEM_OTHER_FLMASK;
22932309
}
2310+
#define shmem_initxattrs NULL
2311+
#endif
22942312

22952313
static struct inode *shmem_get_inode(struct super_block *sb, struct inode *dir,
22962314
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,
23192337
info->i_crtime = inode->i_mtime;
23202338
info->fsflags = (dir == NULL) ? 0 :
23212339
SHMEM_I(dir)->fsflags & SHMEM_FL_INHERITED;
2322-
info->fsflags = shmem_mask_flags(mode, info->fsflags);
2340+
if (info->fsflags)
2341+
shmem_set_inode_flags(inode, info->fsflags);
23232342
INIT_LIST_HEAD(&info->shrinklist);
23242343
INIT_LIST_HEAD(&info->swaplist);
23252344
simple_xattrs_init(&info->xattrs);
@@ -2468,12 +2487,6 @@ int shmem_mfill_atomic_pte(struct mm_struct *dst_mm,
24682487
static const struct inode_operations shmem_symlink_inode_operations;
24692488
static const struct inode_operations shmem_short_symlink_operations;
24702489

2471-
#ifdef CONFIG_TMPFS_XATTR
2472-
static int shmem_initxattrs(struct inode *, const struct xattr *, void *);
2473-
#else
2474-
#define shmem_initxattrs NULL
2475-
#endif
2476-
24772490
static int
24782491
shmem_write_begin(struct file *file, struct address_space *mapping,
24792492
loff_t pos, unsigned len,
@@ -3179,18 +3192,13 @@ static int shmem_fileattr_set(struct user_namespace *mnt_userns,
31793192

31803193
if (fileattr_has_fsx(fa))
31813194
return -EOPNOTSUPP;
3195+
if (fa->flags & ~SHMEM_FL_USER_MODIFIABLE)
3196+
return -EOPNOTSUPP;
31823197

31833198
info->fsflags = (info->fsflags & ~SHMEM_FL_USER_MODIFIABLE) |
31843199
(fa->flags & SHMEM_FL_USER_MODIFIABLE);
31853200

3186-
inode->i_flags &= ~(S_APPEND | S_IMMUTABLE | S_NOATIME);
3187-
if (info->fsflags & FS_APPEND_FL)
3188-
inode->i_flags |= S_APPEND;
3189-
if (info->fsflags & FS_IMMUTABLE_FL)
3190-
inode->i_flags |= S_IMMUTABLE;
3191-
if (info->fsflags & FS_NOATIME_FL)
3192-
inode->i_flags |= S_NOATIME;
3193-
3201+
shmem_set_inode_flags(inode, info->fsflags);
31943202
inode->i_ctime = current_time(inode);
31953203
return 0;
31963204
}

0 commit comments

Comments
 (0)