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 <krisman@suse.de>
Reviewed-by: Gabriel Krisman Bertazi <gabriel@krisman.be>
Signed-off-by: André Almeida <andrealmeid@igalia.com>
Link: https://lore.kernel.org/r/20241021-tonyk-tmpfs-v8-7-f443d5814194@igalia.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
André Almeida 2024-10-21 13:37:23 -03:00 committed by Christian Brauner
parent 58e55efd6c
commit 5cd9aecbc7
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2
2 changed files with 67 additions and 9 deletions

View File

@ -42,10 +42,10 @@ struct shmem_inode_info {
struct inode vfs_inode;
};
#define SHMEM_FL_USER_VISIBLE FS_FL_USER_VISIBLE
#define SHMEM_FL_USER_VISIBLE (FS_FL_USER_VISIBLE | FS_CASEFOLD_FL)
#define SHMEM_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)
(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL | FS_NOATIME_FL | FS_CASEFOLD_FL)
#define SHMEM_FL_INHERITED (FS_NODUMP_FL | FS_NOATIME_FL | FS_CASEFOLD_FL)
struct shmem_quota_limits {
qsize_t usrquota_bhardlimit; /* Default user quota block hard limit */

View File

@ -2757,13 +2757,62 @@ static int shmem_file_open(struct inode *inode, struct file *file)
#ifdef CONFIG_TMPFS_XATTR
static int shmem_initxattrs(struct inode *, const struct xattr *, void *);
#if IS_ENABLED(CONFIG_UNICODE)
/*
* shmem_inode_casefold_flags - Deal with casefold file attribute flag
*
* The casefold file attribute needs some special checks. I can just be added to
* an empty dir, and can't be removed from a non-empty dir.
*/
static int shmem_inode_casefold_flags(struct inode *inode, unsigned int fsflags,
struct dentry *dentry, unsigned int *i_flags)
{
unsigned int old = inode->i_flags;
struct super_block *sb = inode->i_sb;
if (fsflags & FS_CASEFOLD_FL) {
if (!(old & S_CASEFOLD)) {
if (!sb->s_encoding)
return -EOPNOTSUPP;
if (!S_ISDIR(inode->i_mode))
return -ENOTDIR;
if (dentry && !simple_empty(dentry))
return -ENOTEMPTY;
}
*i_flags = *i_flags | S_CASEFOLD;
} else if (old & S_CASEFOLD) {
if (dentry && !simple_empty(dentry))
return -ENOTEMPTY;
}
return 0;
}
#else
static int shmem_inode_casefold_flags(struct inode *inode, unsigned int fsflags,
struct dentry *dentry, unsigned int *i_flags)
{
if (fsflags & FS_CASEFOLD_FL)
return -EOPNOTSUPP;
return 0;
}
#endif
/*
* 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)
static int shmem_set_inode_flags(struct inode *inode, unsigned int fsflags, struct dentry *dentry)
{
unsigned int i_flags = 0;
int ret;
ret = shmem_inode_casefold_flags(inode, fsflags, dentry, &i_flags);
if (ret)
return ret;
if (fsflags & FS_NOATIME_FL)
i_flags |= S_NOATIME;
@ -2774,10 +2823,12 @@ static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags)
/*
* But FS_NODUMP_FL does not require any action in i_flags.
*/
inode_set_flags(inode, i_flags, S_NOATIME | S_APPEND | S_IMMUTABLE);
inode_set_flags(inode, i_flags, S_NOATIME | S_APPEND | S_IMMUTABLE | S_CASEFOLD);
return 0;
}
#else
static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags)
static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags, struct dentry *dentry)
{
}
#define shmem_initxattrs NULL
@ -2824,7 +2875,7 @@ static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
info->fsflags = (dir == NULL) ? 0 :
SHMEM_I(dir)->fsflags & SHMEM_FL_INHERITED;
if (info->fsflags)
shmem_set_inode_flags(inode, info->fsflags);
shmem_set_inode_flags(inode, info->fsflags, NULL);
INIT_LIST_HEAD(&info->shrinklist);
INIT_LIST_HEAD(&info->swaplist);
simple_xattrs_init(&info->xattrs);
@ -3931,16 +3982,23 @@ static int shmem_fileattr_set(struct mnt_idmap *idmap,
{
struct inode *inode = d_inode(dentry);
struct shmem_inode_info *info = SHMEM_I(inode);
int ret, flags;
if (fileattr_has_fsx(fa))
return -EOPNOTSUPP;
if (fa->flags & ~SHMEM_FL_USER_MODIFIABLE)
return -EOPNOTSUPP;
info->fsflags = (info->fsflags & ~SHMEM_FL_USER_MODIFIABLE) |
flags = (info->fsflags & ~SHMEM_FL_USER_MODIFIABLE) |
(fa->flags & SHMEM_FL_USER_MODIFIABLE);
shmem_set_inode_flags(inode, info->fsflags);
ret = shmem_set_inode_flags(inode, flags, dentry);
if (ret)
return ret;
info->fsflags = flags;
inode_set_ctime_current(inode);
inode_inc_iversion(inode);
return 0;