@@ -2757,13 +2757,62 @@ static int shmem_file_open(struct inode *inode, struct file *file)
27572757#ifdef CONFIG_TMPFS_XATTR
27582758static 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