mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-04 04:02:26 +00:00
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:
parent
58e55efd6c
commit
5cd9aecbc7
@ -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 */
|
||||
|
70
mm/shmem.c
70
mm/shmem.c
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user