ext4: use generic casefolding support
authorDaniel Rosenberg <drosen@google.com>
Wed, 28 Oct 2020 05:08:20 +0000 (05:08 +0000)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 28 Oct 2020 17:43:13 +0000 (13:43 -0400)
This switches ext4 over to the generic support provided in libfs.

Since casefolded dentries behave the same in ext4 and f2fs, we decrease
the maintenance burden by unifying them, and any optimizations will
immediately apply to both.

Signed-off-by: Daniel Rosenberg <drosen@google.com>
Reviewed-by: Eric Biggers <ebiggers@google.com>
Link: https://lore.kernel.org/r/20201028050820.1636571-1-drosen@google.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/dir.c
fs/ext4/ext4.h
fs/ext4/hash.c
fs/ext4/namei.c
fs/ext4/super.c

index 5b81f3b080ee605317c465332f343b35e27c5ce7..ca50c90adc4c48796de1d766c686345bf9ece94a 100644 (file)
@@ -669,68 +669,8 @@ const struct file_operations ext4_dir_operations = {
 };
 
 #ifdef CONFIG_UNICODE
-static int ext4_d_compare(const struct dentry *dentry, unsigned int len,
-                         const char *str, const struct qstr *name)
-{
-       struct qstr qstr = {.name = str, .len = len };
-       const struct dentry *parent = READ_ONCE(dentry->d_parent);
-       const struct inode *inode = d_inode_rcu(parent);
-       char strbuf[DNAME_INLINE_LEN];
-
-       if (!inode || !IS_CASEFOLDED(inode) ||
-           !EXT4_SB(inode->i_sb)->s_encoding) {
-               if (len != name->len)
-                       return -1;
-               return memcmp(str, name->name, len);
-       }
-
-       /*
-        * If the dentry name is stored in-line, then it may be concurrently
-        * modified by a rename.  If this happens, the VFS will eventually retry
-        * the lookup, so it doesn't matter what ->d_compare() returns.
-        * However, it's unsafe to call utf8_strncasecmp() with an unstable
-        * string.  Therefore, we have to copy the name into a temporary buffer.
-        */
-       if (len <= DNAME_INLINE_LEN - 1) {
-               memcpy(strbuf, str, len);
-               strbuf[len] = 0;
-               qstr.name = strbuf;
-               /* prevent compiler from optimizing out the temporary buffer */
-               barrier();
-       }
-
-       return ext4_ci_compare(inode, name, &qstr, false);
-}
-
-static int ext4_d_hash(const struct dentry *dentry, struct qstr *str)
-{
-       const struct ext4_sb_info *sbi = EXT4_SB(dentry->d_sb);
-       const struct unicode_map *um = sbi->s_encoding;
-       const struct inode *inode = d_inode_rcu(dentry);
-       unsigned char *norm;
-       int len, ret = 0;
-
-       if (!inode || !IS_CASEFOLDED(inode) || !um)
-               return 0;
-
-       norm = kmalloc(PATH_MAX, GFP_ATOMIC);
-       if (!norm)
-               return -ENOMEM;
-
-       len = utf8_casefold(um, str, norm, PATH_MAX);
-       if (len < 0) {
-               if (ext4_has_strict_mode(sbi))
-                       ret = -EINVAL;
-               goto out;
-       }
-       str->hash = full_name_hash(dentry, norm, len);
-out:
-       kfree(norm);
-       return ret;
-}
-
 const struct dentry_operations ext4_dentry_ops = {
-       .d_hash = ext4_d_hash,
-       .d_compare = ext4_d_compare,
+       .d_hash = generic_ci_d_hash,
+       .d_compare = generic_ci_d_compare,
 };
 #endif
index 2337e443fa30f700fb983c3ff42ec0d378fbe529..45fcdbf538d1198257f75af5a090eb6920df9c15 100644 (file)
@@ -1443,14 +1443,6 @@ struct ext4_super_block {
 
 #define EXT4_ENC_UTF8_12_1     1
 
-/*
- * Flags for ext4_sb_info.s_encoding_flags.
- */
-#define EXT4_ENC_STRICT_MODE_FL        (1 << 0)
-
-#define ext4_has_strict_mode(sbi) \
-       (sbi->s_encoding_flags & EXT4_ENC_STRICT_MODE_FL)
-
 /*
  * fourth extended-fs super-block data in memory
  */
@@ -1500,10 +1492,6 @@ struct ext4_sb_info {
        struct kobject s_kobj;
        struct completion s_kobj_unregister;
        struct super_block *s_sb;
-#ifdef CONFIG_UNICODE
-       struct unicode_map *s_encoding;
-       __u16 s_encoding_flags;
-#endif
 
        /* Journaling */
        struct journal_s *s_journal;
index 2924261226e0fa6dcc83f849125e0a879b0f869f..a92eb79de0cc7fedd2f53cc369348846396e24f3 100644 (file)
@@ -275,7 +275,7 @@ int ext4fs_dirhash(const struct inode *dir, const char *name, int len,
                   struct dx_hash_info *hinfo)
 {
 #ifdef CONFIG_UNICODE
-       const struct unicode_map *um = EXT4_SB(dir->i_sb)->s_encoding;
+       const struct unicode_map *um = dir->i_sb->s_encoding;
        int r, dlen;
        unsigned char *buff;
        struct qstr qstr = {.name = name, .len = len };
index 5159830dacb8aa61656b34784cd704fb82f811b5..f458d1d81d96b4858a2cc477f2a907e0fa755c0d 100644 (file)
@@ -1285,8 +1285,8 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block)
 int ext4_ci_compare(const struct inode *parent, const struct qstr *name,
                    const struct qstr *entry, bool quick)
 {
-       const struct ext4_sb_info *sbi = EXT4_SB(parent->i_sb);
-       const struct unicode_map *um = sbi->s_encoding;
+       const struct super_block *sb = parent->i_sb;
+       const struct unicode_map *um = sb->s_encoding;
        int ret;
 
        if (quick)
@@ -1298,7 +1298,7 @@ int ext4_ci_compare(const struct inode *parent, const struct qstr *name,
                /* Handle invalid character sequence as either an error
                 * or as an opaque byte sequence.
                 */
-               if (ext4_has_strict_mode(sbi))
+               if (sb_has_strict_encoding(sb))
                        return -EINVAL;
 
                if (name->len != entry->len)
@@ -1315,7 +1315,7 @@ void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
 {
        int len;
 
-       if (!IS_CASEFOLDED(dir) || !EXT4_SB(dir->i_sb)->s_encoding) {
+       if (!IS_CASEFOLDED(dir) || !dir->i_sb->s_encoding) {
                cf_name->name = NULL;
                return;
        }
@@ -1324,7 +1324,7 @@ void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
        if (!cf_name->name)
                return;
 
-       len = utf8_casefold(EXT4_SB(dir->i_sb)->s_encoding,
+       len = utf8_casefold(dir->i_sb->s_encoding,
                            iname, cf_name->name,
                            EXT4_NAME_LEN);
        if (len <= 0) {
@@ -1361,7 +1361,7 @@ static inline bool ext4_match(const struct inode *parent,
 #endif
 
 #ifdef CONFIG_UNICODE
-       if (EXT4_SB(parent->i_sb)->s_encoding && IS_CASEFOLDED(parent)) {
+       if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent)) {
                if (fname->cf_name.name) {
                        struct qstr cf = {.name = fname->cf_name.name,
                                          .len = fname->cf_name.len};
@@ -2180,9 +2180,6 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
        struct buffer_head *bh = NULL;
        struct ext4_dir_entry_2 *de;
        struct super_block *sb;
-#ifdef CONFIG_UNICODE
-       struct ext4_sb_info *sbi;
-#endif
        struct ext4_filename fname;
        int     retval;
        int     dx_fallback=0;
@@ -2199,9 +2196,8 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
                return -EINVAL;
 
 #ifdef CONFIG_UNICODE
-       sbi = EXT4_SB(sb);
-       if (ext4_has_strict_mode(sbi) && IS_CASEFOLDED(dir) &&
-           sbi->s_encoding && utf8_validate(sbi->s_encoding, &dentry->d_name))
+       if (sb_has_strict_encoding(sb) && IS_CASEFOLDED(dir) &&
+           sb->s_encoding && utf8_validate(sb->s_encoding, &dentry->d_name))
                return -EINVAL;
 #endif
 
index d92de21212e937d45dee9716723574028ba17201..0f5a3149839331744e3cd568c6e115f39e5b5851 100644 (file)
@@ -1288,7 +1288,7 @@ static void ext4_put_super(struct super_block *sb)
        fs_put_dax(sbi->s_daxdev);
        fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
 #ifdef CONFIG_UNICODE
-       utf8_unload(sbi->s_encoding);
+       utf8_unload(sb->s_encoding);
 #endif
        kfree(sbi);
 }
@@ -4303,7 +4303,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                goto failed_mount;
 
 #ifdef CONFIG_UNICODE
-       if (ext4_has_feature_casefold(sb) && !sbi->s_encoding) {
+       if (ext4_has_feature_casefold(sb) && !sb->s_encoding) {
                const struct ext4_sb_encodings *encoding_info;
                struct unicode_map *encoding;
                __u16 encoding_flags;
@@ -4334,8 +4334,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                         "%s-%s with flags 0x%hx", encoding_info->name,
                         encoding_info->version?:"\b", encoding_flags);
 
-               sbi->s_encoding = encoding;
-               sbi->s_encoding_flags = encoding_flags;
+               sb->s_encoding = encoding;
+               sb->s_encoding_flags = encoding_flags;
        }
 #endif
 
@@ -4975,7 +4975,7 @@ no_journal:
        }
 
 #ifdef CONFIG_UNICODE
-       if (sbi->s_encoding)
+       if (sb->s_encoding)
                sb->s_d_op = &ext4_dentry_ops;
 #endif
 
@@ -5184,7 +5184,7 @@ failed_mount:
                crypto_free_shash(sbi->s_chksum_driver);
 
 #ifdef CONFIG_UNICODE
-       utf8_unload(sbi->s_encoding);
+       utf8_unload(sb->s_encoding);
 #endif
 
 #ifdef CONFIG_QUOTA