Skip to content

Commit 5cd9aec

Browse files
andrealmeidbrauner
authored andcommitted
tmpfs: Add flag FS_CASEFOLD_FL support for tmpfs dirs
Enable setting flag FS_CASEFOLD_FL for tmpfs directories, when tmpfs is mounted with casefold support. A special check is need for this flag, since it can't be set for non-empty directories. Reviewed-by: Gabriel Krisman Bertazi <[email protected]> Reviewed-by: Gabriel Krisman Bertazi <[email protected]> Signed-off-by: André Almeida <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 58e55ef commit 5cd9aec

File tree

2 files changed

+67
-9
lines changed

2 files changed

+67
-9
lines changed

include/linux/shmem_fs.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ struct shmem_inode_info {
4242
struct inode vfs_inode;
4343
};
4444

45-
#define SHMEM_FL_USER_VISIBLE FS_FL_USER_VISIBLE
45+
#define SHMEM_FL_USER_VISIBLE (FS_FL_USER_VISIBLE | FS_CASEFOLD_FL)
4646
#define SHMEM_FL_USER_MODIFIABLE \
47-
(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL | FS_NOATIME_FL)
48-
#define SHMEM_FL_INHERITED (FS_NODUMP_FL | FS_NOATIME_FL)
47+
(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL | FS_NOATIME_FL | FS_CASEFOLD_FL)
48+
#define SHMEM_FL_INHERITED (FS_NODUMP_FL | FS_NOATIME_FL | FS_CASEFOLD_FL)
4949

5050
struct shmem_quota_limits {
5151
qsize_t usrquota_bhardlimit; /* Default user quota block hard limit */

mm/shmem.c

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2757,13 +2757,62 @@ static int shmem_file_open(struct inode *inode, struct file *file)
27572757
#ifdef CONFIG_TMPFS_XATTR
27582758
static int shmem_initxattrs(struct inode *, const struct xattr *, void *);
27592759

2760+
#if IS_ENABLED(CONFIG_UNICODE)
2761+
/*
2762+
* shmem_inode_casefold_flags - Deal with casefold file attribute flag
2763+
*
2764+
* The casefold file attribute needs some special checks. I can just be added to
2765+
* an empty dir, and can't be removed from a non-empty dir.
2766+
*/
2767+
static int shmem_inode_casefold_flags(struct inode *inode, unsigned int fsflags,
2768+
struct dentry *dentry, unsigned int *i_flags)
2769+
{
2770+
unsigned int old = inode->i_flags;
2771+
struct super_block *sb = inode->i_sb;
2772+
2773+
if (fsflags & FS_CASEFOLD_FL) {
2774+
if (!(old & S_CASEFOLD)) {
2775+
if (!sb->s_encoding)
2776+
return -EOPNOTSUPP;
2777+
2778+
if (!S_ISDIR(inode->i_mode))
2779+
return -ENOTDIR;
2780+
2781+
if (dentry && !simple_empty(dentry))
2782+
return -ENOTEMPTY;
2783+
}
2784+
2785+
*i_flags = *i_flags | S_CASEFOLD;
2786+
} else if (old & S_CASEFOLD) {
2787+
if (dentry && !simple_empty(dentry))
2788+
return -ENOTEMPTY;
2789+
}
2790+
2791+
return 0;
2792+
}
2793+
#else
2794+
static int shmem_inode_casefold_flags(struct inode *inode, unsigned int fsflags,
2795+
struct dentry *dentry, unsigned int *i_flags)
2796+
{
2797+
if (fsflags & FS_CASEFOLD_FL)
2798+
return -EOPNOTSUPP;
2799+
2800+
return 0;
2801+
}
2802+
#endif
2803+
27602804
/*
27612805
* chattr's fsflags are unrelated to extended attributes,
27622806
* but tmpfs has chosen to enable them under the same config option.
27632807
*/
2764-
static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags)
2808+
static int shmem_set_inode_flags(struct inode *inode, unsigned int fsflags, struct dentry *dentry)
27652809
{
27662810
unsigned int i_flags = 0;
2811+
int ret;
2812+
2813+
ret = shmem_inode_casefold_flags(inode, fsflags, dentry, &i_flags);
2814+
if (ret)
2815+
return ret;
27672816

27682817
if (fsflags & FS_NOATIME_FL)
27692818
i_flags |= S_NOATIME;
@@ -2774,10 +2823,12 @@ static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags)
27742823
/*
27752824
* But FS_NODUMP_FL does not require any action in i_flags.
27762825
*/
2777-
inode_set_flags(inode, i_flags, S_NOATIME | S_APPEND | S_IMMUTABLE);
2826+
inode_set_flags(inode, i_flags, S_NOATIME | S_APPEND | S_IMMUTABLE | S_CASEFOLD);
2827+
2828+
return 0;
27782829
}
27792830
#else
2780-
static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags)
2831+
static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags, struct dentry *dentry)
27812832
{
27822833
}
27832834
#define shmem_initxattrs NULL
@@ -2824,7 +2875,7 @@ static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
28242875
info->fsflags = (dir == NULL) ? 0 :
28252876
SHMEM_I(dir)->fsflags & SHMEM_FL_INHERITED;
28262877
if (info->fsflags)
2827-
shmem_set_inode_flags(inode, info->fsflags);
2878+
shmem_set_inode_flags(inode, info->fsflags, NULL);
28282879
INIT_LIST_HEAD(&info->shrinklist);
28292880
INIT_LIST_HEAD(&info->swaplist);
28302881
simple_xattrs_init(&info->xattrs);
@@ -3931,16 +3982,23 @@ static int shmem_fileattr_set(struct mnt_idmap *idmap,
39313982
{
39323983
struct inode *inode = d_inode(dentry);
39333984
struct shmem_inode_info *info = SHMEM_I(inode);
3985+
int ret, flags;
39343986

39353987
if (fileattr_has_fsx(fa))
39363988
return -EOPNOTSUPP;
39373989
if (fa->flags & ~SHMEM_FL_USER_MODIFIABLE)
39383990
return -EOPNOTSUPP;
39393991

3940-
info->fsflags = (info->fsflags & ~SHMEM_FL_USER_MODIFIABLE) |
3992+
flags = (info->fsflags & ~SHMEM_FL_USER_MODIFIABLE) |
39413993
(fa->flags & SHMEM_FL_USER_MODIFIABLE);
39423994

3943-
shmem_set_inode_flags(inode, info->fsflags);
3995+
ret = shmem_set_inode_flags(inode, flags, dentry);
3996+
3997+
if (ret)
3998+
return ret;
3999+
4000+
info->fsflags = flags;
4001+
39444002
inode_set_ctime_current(inode);
39454003
inode_inc_iversion(inode);
39464004
return 0;

0 commit comments

Comments
 (0)