2022-05-18 17:25:15

by Gabriel Krisman Bertazi

[permalink] [raw]
Subject: [PATCH v5 0/8] Clean up the case-insensitive lookup path

Hi Eric, Ted,

This reworks the entire series to apply Eric's comments. Thank you for
the feedback, Eric!

The biggest change is the removal of unicode_name and the split of the
libfs patch. It made the series much better to follow. I also dropped
the hash patch, but there is still a minor cleanup on that code flow in
patch 4 ("ext4: Reuse generic_ci_match for ci comparisons"). I'd
appreciate your review there regarding fscrypt semantics.

This survives the quick group and generic/556 (casefold) tests.

* Original commit letter

The case-insensitive implementations in f2fs and ext4 have quite a bit
of duplicated code. This series simplifies the ext4 version, with the
goal of extracting ext4_ci_compare into a helper library that can be
used by both filesystems. It also reduces the clutter from many
codeguards for CONFIG_UNICODE; as requested by Linus, they are part of
the codeflow now.

While there, I noticed we can leverage the utf8 functions to detect
encoded names that are corrupted in the filesystem. Therefore, it also
adds an ext4 error on that scenario, to mark the filesystem as
corrupted.

This series survived passes of xfstests -g quick.

Gabriel Krisman Bertazi (8):
ext4: Simplify the handling of cached insensitive names
f2fs: Simplify the handling of cached insensitive names
libfs: Introduce case-insensitive string comparison helper
ext4: Reuse generic_ci_match for ci comparisons
f2fs: Reuse generic_ci_match for ci comparisons
ext4: Log error when lookup of encoded dentry fails
ext4: Move CONFIG_UNICODE defguards into the code flow
f2fs: Move CONFIG_UNICODE defguards into the code flow

fs/ext4/ext4.h | 39 ++++++++-------
fs/ext4/namei.c | 120 ++++++++++++++-------------------------------
fs/ext4/super.c | 4 +-
fs/f2fs/dir.c | 103 ++++++++++++--------------------------
fs/f2fs/f2fs.h | 15 +++++-
fs/f2fs/namei.c | 11 ++---
fs/f2fs/recovery.c | 5 +-
fs/f2fs/super.c | 8 +--
fs/libfs.c | 65 ++++++++++++++++++++++++
include/linux/fs.h | 4 ++
10 files changed, 181 insertions(+), 193 deletions(-)

--
2.36.1



2022-05-18 17:25:15

by Gabriel Krisman Bertazi

[permalink] [raw]
Subject: [PATCH v5 1/8] ext4: Simplify the handling of cached insensitive names

Keeping it as qstr avoids the unnecessary conversion in ext4_match

Signed-off-by: Gabriel Krisman Bertazi <[email protected]>

--
Changes since v1:
- Simplify hunk (eric)
---
fs/ext4/ext4.h | 2 +-
fs/ext4/namei.c | 23 +++++++++++------------
2 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index a743b1e3b89e..93a28fcb2e22 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2490,7 +2490,7 @@ struct ext4_filename {
struct fscrypt_str crypto_buf;
#endif
#if IS_ENABLED(CONFIG_UNICODE)
- struct fscrypt_str cf_name;
+ struct qstr cf_name;
#endif
};

diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 767b4bfe39c3..206fcf8fdc16 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1373,7 +1373,8 @@ static int ext4_ci_compare(const struct inode *parent, const struct qstr *name,
int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
struct ext4_filename *name)
{
- struct fscrypt_str *cf_name = &name->cf_name;
+ struct qstr *cf_name = &name->cf_name;
+ unsigned char *buf;
struct dx_hash_info *hinfo = &name->hinfo;
int len;

@@ -1383,18 +1384,18 @@ int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
return 0;
}

- cf_name->name = kmalloc(EXT4_NAME_LEN, GFP_NOFS);
- if (!cf_name->name)
+ buf = kmalloc(EXT4_NAME_LEN, GFP_NOFS);
+ if (!buf)
return -ENOMEM;

- len = utf8_casefold(dir->i_sb->s_encoding,
- iname, cf_name->name,
- EXT4_NAME_LEN);
+ len = utf8_casefold(dir->i_sb->s_encoding, iname, buf, EXT4_NAME_LEN);
if (len <= 0) {
- kfree(cf_name->name);
- cf_name->name = NULL;
+ kfree(buf);
+ buf = NULL;
}
+ cf_name->name = buf;
cf_name->len = (unsigned) len;
+
if (!IS_ENCRYPTED(dir))
return 0;

@@ -1432,8 +1433,6 @@ static bool ext4_match(struct inode *parent,
if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent) &&
(!IS_ENCRYPTED(parent) || fscrypt_has_encryption_key(parent))) {
if (fname->cf_name.name) {
- struct qstr cf = {.name = fname->cf_name.name,
- .len = fname->cf_name.len};
if (IS_ENCRYPTED(parent)) {
if (fname->hinfo.hash != EXT4_DIRENT_HASH(de) ||
fname->hinfo.minor_hash !=
@@ -1442,8 +1441,8 @@ static bool ext4_match(struct inode *parent,
return false;
}
}
- return !ext4_ci_compare(parent, &cf, de->name,
- de->name_len, true);
+ return !ext4_ci_compare(parent, &fname->cf_name,
+ de->name, de->name_len, true);
}
return !ext4_ci_compare(parent, fname->usr_fname, de->name,
de->name_len, false);
--
2.36.1


2022-05-18 17:25:15

by Gabriel Krisman Bertazi

[permalink] [raw]
Subject: [PATCH v5 2/8] f2fs: Simplify the handling of cached insensitive names

Keeping it as qstr avoids the unnecessary conversion in f2fs_match

Signed-off-by: Gabriel Krisman Bertazi <[email protected]>

---
Changes since v4:
- Fix inconsistent return on error (eric)
---
fs/f2fs/dir.c | 51 ++++++++++++++++++++++++++--------------------
fs/f2fs/f2fs.h | 15 +++++++++++++-
fs/f2fs/recovery.c | 5 +----
3 files changed, 44 insertions(+), 27 deletions(-)

diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 166f08623362..167a04074a2e 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -75,34 +75,48 @@ unsigned char f2fs_get_de_type(struct f2fs_dir_entry *de)
return DT_UNKNOWN;
}

+#if IS_ENABLED(CONFIG_UNICODE)
/* If @dir is casefolded, initialize @fname->cf_name from @fname->usr_fname. */
int f2fs_init_casefolded_name(const struct inode *dir,
struct f2fs_filename *fname)
{
-#if IS_ENABLED(CONFIG_UNICODE)
struct super_block *sb = dir->i_sb;
+ unsigned char *buf;
+ int len;

if (IS_CASEFOLDED(dir)) {
- fname->cf_name.name = f2fs_kmem_cache_alloc(f2fs_cf_name_slab,
+ buf = f2fs_kmem_cache_alloc(f2fs_cf_name_slab,
GFP_NOFS, false, F2FS_SB(sb));
- if (!fname->cf_name.name)
+ if (!buf)
return -ENOMEM;
- fname->cf_name.len = utf8_casefold(sb->s_encoding,
- fname->usr_fname,
- fname->cf_name.name,
- F2FS_NAME_LEN);
- if ((int)fname->cf_name.len <= 0) {
- kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name);
- fname->cf_name.name = NULL;
+
+ len = utf8_casefold(sb->s_encoding, fname->usr_fname,
+ buf, F2FS_NAME_LEN);
+ if (len <= 0) {
+ kmem_cache_free(f2fs_cf_name_slab, buf);
if (sb_has_strict_encoding(sb))
return -EINVAL;
/* fall back to treating name as opaque byte sequence */
+ return 0;
}
+ fname->cf_name.name = buf;
+ fname->cf_name.len = len;
}
-#endif
+
return 0;
}

+void f2fs_free_casefolded_name(struct f2fs_filename *fname)
+{
+ unsigned char *buf = (unsigned char *)fname->cf_name.name;
+
+ if (buf) {
+ kmem_cache_free(f2fs_cf_name_slab, buf);
+ fname->cf_name.name = NULL;
+ }
+}
+#endif /* CONFIG_UNICODE */
+
static int __f2fs_setup_filename(const struct inode *dir,
const struct fscrypt_name *crypt_name,
struct f2fs_filename *fname)
@@ -174,12 +188,7 @@ void f2fs_free_filename(struct f2fs_filename *fname)
kfree(fname->crypto_buf.name);
fname->crypto_buf.name = NULL;
#endif
-#if IS_ENABLED(CONFIG_UNICODE)
- if (fname->cf_name.name) {
- kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name);
- fname->cf_name.name = NULL;
- }
-#endif
+ f2fs_free_casefolded_name(fname);
}

static unsigned long dir_block_index(unsigned int level,
@@ -267,11 +276,9 @@ static inline int f2fs_match_name(const struct inode *dir,
struct fscrypt_name f;

#if IS_ENABLED(CONFIG_UNICODE)
- if (fname->cf_name.name) {
- struct qstr cf = FSTR_TO_QSTR(&fname->cf_name);
-
- return f2fs_match_ci_name(dir, &cf, de_name, de_name_len);
- }
+ if (fname->cf_name.name)
+ return f2fs_match_ci_name(dir, &fname->cf_name,
+ de_name, de_name_len);
#endif
f.usr_fname = fname->usr_fname;
f.disk_name = fname->disk_name;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 68b44015514f..5eb88be507e7 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -497,7 +497,7 @@ struct f2fs_filename {
* NULL. In all these cases we fall back to treating the name as an
* opaque byte sequence.
*/
- struct fscrypt_str cf_name;
+ struct qstr cf_name;
#endif
};

@@ -3343,8 +3343,21 @@ struct dentry *f2fs_get_parent(struct dentry *child);
* dir.c
*/
unsigned char f2fs_get_de_type(struct f2fs_dir_entry *de);
+#if IS_ENABLED(CONFIG_UNICODE)
int f2fs_init_casefolded_name(const struct inode *dir,
struct f2fs_filename *fname);
+void f2fs_free_casefolded_name(struct f2fs_filename *fname);
+#else
+static inline int f2fs_init_casefolded_name(const struct inode *dir,
+ struct f2fs_filename *fname)
+{
+ return 0;
+}
+static inline void f2fs_free_casefolded_name(struct f2fs_filename *fname)
+{
+}
+#endif /* CONFIG_UNICODE */
+
int f2fs_setup_filename(struct inode *dir, const struct qstr *iname,
int lookup, struct f2fs_filename *fname);
int f2fs_prepare_lookup(struct inode *dir, struct dentry *dentry,
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index 79773d322c47..3c3a8abf6953 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -149,11 +149,8 @@ static int init_recovered_filename(const struct inode *dir,
if (err)
return err;
f2fs_hash_filename(dir, fname);
-#if IS_ENABLED(CONFIG_UNICODE)
/* Case-sensitive match is fine for recovery */
- kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name);
- fname->cf_name.name = NULL;
-#endif
+ f2fs_free_casefolded_name(fname);
} else {
f2fs_hash_filename(dir, fname);
}
--
2.36.1


2022-05-18 17:25:17

by Gabriel Krisman Bertazi

[permalink] [raw]
Subject: [PATCH v5 3/8] libfs: Introduce case-insensitive string comparison helper

generic_ci_match can be used by case-insensitive filesystems to compare
strings under lookup with dirents in a case-insensitive way. This
function is currently reimplemented by each filesystem supporting
casefolding, so this reduces code duplication in filesystem-specific
code.

Signed-off-by: Gabriel Krisman Bertazi <[email protected]>
---
fs/libfs.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/fs.h | 4 +++
2 files changed, 69 insertions(+)

diff --git a/fs/libfs.c b/fs/libfs.c
index 974125270a42..6861d43563be 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -1465,6 +1465,71 @@ static const struct dentry_operations generic_ci_dentry_ops = {
.d_hash = generic_ci_d_hash,
.d_compare = generic_ci_d_compare,
};
+
+/**
+ * generic_ci_match() - Match a name (case-insensitively) name with a dirent.
+ * @parent: Inode of the parent of the dirent under comparison
+ * @name: name under lookup.
+ * @folded_name: Optional pre-folded name under lookup
+ * @de_name: Dirent name.
+ * @de_name_len: dirent name length.
+ *
+ *
+ * Test whether a case-insensitive directory entry matches the filename
+ * being searched. If @folded_name is provided, it is used instead of
+ * recalculating the casefold of @name.
+ *
+ * Return: > 0 if the directory entry matches, 0 if it doesn't match, or
+ * < 0 on error.
+ */
+int generic_ci_match(const struct inode *parent,
+ const struct qstr *name,
+ const struct qstr *folded_name,
+ const u8 *de_name, size_t de_name_len)
+{
+ const struct super_block *sb = parent->i_sb;
+ const struct unicode_map *um = sb->s_encoding;
+ struct fscrypt_str decrypted_name = FSTR_INIT(NULL, de_name_len);
+ struct qstr dirent = QSTR_INIT(de_name, de_name_len);
+ int err, match = false;
+
+ if (IS_ENCRYPTED(parent)) {
+ const struct fscrypt_str encrypted_name =
+ FSTR_INIT((u8 *) de_name, de_name_len);
+
+ decrypted_name.name = kmalloc(de_name_len, GFP_KERNEL);
+ if (!decrypted_name.name)
+ return -ENOMEM;
+ err = fscrypt_fname_disk_to_usr(parent, 0, 0, &encrypted_name,
+ &decrypted_name);
+ if (err < 0)
+ goto out;
+ dirent.name = decrypted_name.name;
+ dirent.len = decrypted_name.len;
+ }
+
+ if (folded_name->name)
+ err = utf8_strncasecmp_folded(um, folded_name, &dirent);
+ else
+ err = utf8_strncasecmp(um, name, &dirent);
+
+ if (!err)
+ match = true;
+ else if (err < 0 && !sb_has_strict_encoding(sb)) {
+ /*
+ * In non-strict mode, fallback to a byte comparison if
+ * the names have invalid characters.
+ */
+ err = 0;
+ match = ((name->len == dirent.len) &&
+ !memcmp(name->name, dirent.name, dirent.len));
+ }
+
+out:
+ kfree(decrypted_name.name);
+ return (err >= 0) ? match : err;
+}
+EXPORT_SYMBOL(generic_ci_match);
#endif

#ifdef CONFIG_FS_ENCRYPTION
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e2d892b201b0..7a0214bfac34 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3359,6 +3359,10 @@ extern int generic_file_fsync(struct file *, loff_t, loff_t, int);
extern int generic_check_addressable(unsigned, u64);

extern void generic_set_encrypted_ci_d_ops(struct dentry *dentry);
+extern int generic_ci_match(const struct inode *parent,
+ const struct qstr *name,
+ const struct qstr *folded_name,
+ const u8 *de_name, size_t de_name_len);

#ifdef CONFIG_MIGRATION
extern int buffer_migrate_page(struct address_space *,
--
2.36.1


2022-05-18 17:25:17

by Gabriel Krisman Bertazi

[permalink] [raw]
Subject: [PATCH v5 4/8] ext4: Reuse generic_ci_match for ci comparisons

Instead of reimplementing ext4_match_ci, use the new libfs helper.

Signed-off-by: Gabriel Krisman Bertazi <[email protected]>
---
fs/ext4/namei.c | 81 +++++++++++--------------------------------------
1 file changed, 17 insertions(+), 64 deletions(-)

diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 206fcf8fdc16..98295b03a57c 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1318,58 +1318,6 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block)
}

#if IS_ENABLED(CONFIG_UNICODE)
-/*
- * Test whether a case-insensitive directory entry matches the filename
- * being searched for. If quick is set, assume the name being looked up
- * is already in the casefolded form.
- *
- * Returns: 0 if the directory entry matches, more than 0 if it
- * doesn't match or less than zero on error.
- */
-static int ext4_ci_compare(const struct inode *parent, const struct qstr *name,
- u8 *de_name, size_t de_name_len, bool quick)
-{
- const struct super_block *sb = parent->i_sb;
- const struct unicode_map *um = sb->s_encoding;
- struct fscrypt_str decrypted_name = FSTR_INIT(NULL, de_name_len);
- struct qstr entry = QSTR_INIT(de_name, de_name_len);
- int ret;
-
- if (IS_ENCRYPTED(parent)) {
- const struct fscrypt_str encrypted_name =
- FSTR_INIT(de_name, de_name_len);
-
- decrypted_name.name = kmalloc(de_name_len, GFP_KERNEL);
- if (!decrypted_name.name)
- return -ENOMEM;
- ret = fscrypt_fname_disk_to_usr(parent, 0, 0, &encrypted_name,
- &decrypted_name);
- if (ret < 0)
- goto out;
- entry.name = decrypted_name.name;
- entry.len = decrypted_name.len;
- }
-
- if (quick)
- ret = utf8_strncasecmp_folded(um, name, &entry);
- else
- ret = utf8_strncasecmp(um, name, &entry);
- if (ret < 0) {
- /* Handle invalid character sequence as either an error
- * or as an opaque byte sequence.
- */
- if (sb_has_strict_encoding(sb))
- ret = -EINVAL;
- else if (name->len != entry.len)
- ret = 1;
- else
- ret = !!memcmp(name->name, entry.name, entry.len);
- }
-out:
- kfree(decrypted_name.name);
- return ret;
-}
-
int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
struct ext4_filename *name)
{
@@ -1432,20 +1380,25 @@ static bool ext4_match(struct inode *parent,
#if IS_ENABLED(CONFIG_UNICODE)
if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent) &&
(!IS_ENCRYPTED(parent) || fscrypt_has_encryption_key(parent))) {
- if (fname->cf_name.name) {
- if (IS_ENCRYPTED(parent)) {
- if (fname->hinfo.hash != EXT4_DIRENT_HASH(de) ||
- fname->hinfo.minor_hash !=
- EXT4_DIRENT_MINOR_HASH(de)) {
+ int ret;

- return false;
- }
- }
- return !ext4_ci_compare(parent, &fname->cf_name,
- de->name, de->name_len, true);
+ if (IS_ENCRYPTED(parent) &&
+ (fname->hinfo.hash != EXT4_DIRENT_HASH(de) ||
+ fname->hinfo.minor_hash != EXT4_DIRENT_MINOR_HASH(de)))
+ return false;
+
+ ret = generic_ci_match(parent, fname->usr_fname,
+ &fname->cf_name, de->name,
+ de->name_len);
+ if (ret < 0) {
+ /*
+ * Treat comparison errors as not a match. The
+ * only case where it happens is on a disk
+ * corruption or ENOMEM.
+ */
+ return false;
}
- return !ext4_ci_compare(parent, fname->usr_fname, de->name,
- de->name_len, false);
+ return ret;
}
#endif

--
2.36.1


2022-05-18 17:25:18

by Gabriel Krisman Bertazi

[permalink] [raw]
Subject: [PATCH v5 6/8] ext4: Log error when lookup of encoded dentry fails

If the volume is in strict mode, ext4_ci_compare can report a broken
encoding name. This will not trigger on a bad lookup, which is caught
earlier, only if the actual disk name is bad.

Signed-off-by: Gabriel Krisman Bertazi <[email protected]>

---

changes since v4:
- Reword error message (Eric)

Changes since v1:
- reword error message "file in directory" -> "filename" (Eric)
---
fs/ext4/namei.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 98295b03a57c..8fbb35187f72 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1396,6 +1396,9 @@ static bool ext4_match(struct inode *parent,
* only case where it happens is on a disk
* corruption or ENOMEM.
*/
+ if (ret == -EINVAL)
+ EXT4_ERROR_INODE(parent,
+ "Directory contains filename that is invalid UTF-8");
return false;
}
return ret;
--
2.36.1


2022-05-18 17:25:18

by Gabriel Krisman Bertazi

[permalink] [raw]
Subject: [PATCH v5 5/8] f2fs: Reuse generic_ci_match for ci comparisons

Now that ci_match is part of libfs, make f2fs reuse it instead of having
a different implementation.

Signed-off-by: Gabriel Krisman Bertazi <[email protected]>

---
Changes since v3:
- fix unused variable iff !CONFIG_UNICODE (lkp)
---
fs/f2fs/dir.c | 58 ++++-----------------------------------------------
1 file changed, 4 insertions(+), 54 deletions(-)

diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 167a04074a2e..9431a3adb355 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -217,58 +217,6 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir,
return f2fs_find_target_dentry(&d, fname, max_slots);
}

-#if IS_ENABLED(CONFIG_UNICODE)
-/*
- * Test whether a case-insensitive directory entry matches the filename
- * being searched for.
- *
- * Returns 1 for a match, 0 for no match, and -errno on an error.
- */
-static int f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
- const u8 *de_name, u32 de_name_len)
-{
- const struct super_block *sb = dir->i_sb;
- const struct unicode_map *um = sb->s_encoding;
- struct fscrypt_str decrypted_name = FSTR_INIT(NULL, de_name_len);
- struct qstr entry = QSTR_INIT(de_name, de_name_len);
- int res;
-
- if (IS_ENCRYPTED(dir)) {
- const struct fscrypt_str encrypted_name =
- FSTR_INIT((u8 *)de_name, de_name_len);
-
- if (WARN_ON_ONCE(!fscrypt_has_encryption_key(dir)))
- return -EINVAL;
-
- decrypted_name.name = kmalloc(de_name_len, GFP_KERNEL);
- if (!decrypted_name.name)
- return -ENOMEM;
- res = fscrypt_fname_disk_to_usr(dir, 0, 0, &encrypted_name,
- &decrypted_name);
- if (res < 0)
- goto out;
- entry.name = decrypted_name.name;
- entry.len = decrypted_name.len;
- }
-
- res = utf8_strncasecmp_folded(um, name, &entry);
- /*
- * In strict mode, ignore invalid names. In non-strict mode,
- * fall back to treating them as opaque byte sequences.
- */
- if (res < 0 && !sb_has_strict_encoding(sb)) {
- res = name->len == entry.len &&
- memcmp(name->name, entry.name, name->len) == 0;
- } else {
- /* utf8_strncasecmp_folded returns 0 on match */
- res = (res == 0);
- }
-out:
- kfree(decrypted_name.name);
- return res;
-}
-#endif /* CONFIG_UNICODE */
-
static inline int f2fs_match_name(const struct inode *dir,
const struct f2fs_filename *fname,
const u8 *de_name, u32 de_name_len)
@@ -277,8 +225,10 @@ static inline int f2fs_match_name(const struct inode *dir,

#if IS_ENABLED(CONFIG_UNICODE)
if (fname->cf_name.name)
- return f2fs_match_ci_name(dir, &fname->cf_name,
- de_name, de_name_len);
+ return generic_ci_match(dir, fname->usr_fname,
+ &fname->cf_name,
+ (u8 *) de_name, de_name_len);
+
#endif
f.usr_fname = fname->usr_fname;
f.disk_name = fname->disk_name;
--
2.36.1


2022-05-18 17:25:18

by Gabriel Krisman Bertazi

[permalink] [raw]
Subject: [PATCH v5 7/8] ext4: Move CONFIG_UNICODE defguards into the code flow

Instead of a bunch of ifdefs, make the unicode built checks part of the
code flow where possible, as requested by Torvalds.

Signed-off-by: Gabriel Krisman Bertazi <[email protected]>

---
Changes since v4:
- Create stub for !CONFIG_UNICODE case (eric)
---
fs/ext4/ext4.h | 37 ++++++++++++++++++++-----------------
fs/ext4/namei.c | 15 ++++++---------
fs/ext4/super.c | 4 +---
3 files changed, 27 insertions(+), 29 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 93a28fcb2e22..c38999ee3627 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2727,8 +2727,24 @@ ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);

#if IS_ENABLED(CONFIG_UNICODE)
extern int ext4_fname_setup_ci_filename(struct inode *dir,
- const struct qstr *iname,
- struct ext4_filename *fname);
+ const struct qstr *iname,
+ struct ext4_filename *fname);
+
+static inline void ext4_fname_free_ci_filename(struct ext4_filename *fname)
+{
+ kfree(fname->cf_name.name);
+ fname->cf_name.name = NULL;
+}
+#else
+static inline int ext4_fname_setup_ci_filename(struct inode *dir,
+ const struct qstr *iname,
+ struct ext4_filename *fname)
+{
+ return 0;
+}
+static inline void ext4_fname_free_ci_filename(struct ext4_filename *fname)
+{
+}
#endif

#ifdef CONFIG_FS_ENCRYPTION
@@ -2758,9 +2774,7 @@ static inline int ext4_fname_setup_filename(struct inode *dir,

ext4_fname_from_fscrypt_name(fname, &name);

-#if IS_ENABLED(CONFIG_UNICODE)
err = ext4_fname_setup_ci_filename(dir, iname, fname);
-#endif
return err;
}

@@ -2777,9 +2791,7 @@ static inline int ext4_fname_prepare_lookup(struct inode *dir,

ext4_fname_from_fscrypt_name(fname, &name);

-#if IS_ENABLED(CONFIG_UNICODE)
err = ext4_fname_setup_ci_filename(dir, &dentry->d_name, fname);
-#endif
return err;
}

@@ -2794,10 +2806,7 @@ static inline void ext4_fname_free_filename(struct ext4_filename *fname)
fname->usr_fname = NULL;
fname->disk_name.name = NULL;

-#if IS_ENABLED(CONFIG_UNICODE)
- kfree(fname->cf_name.name);
- fname->cf_name.name = NULL;
-#endif
+ ext4_fname_free_ci_filename(fname);
}
#else /* !CONFIG_FS_ENCRYPTION */
static inline int ext4_fname_setup_filename(struct inode *dir,
@@ -2810,10 +2819,7 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
fname->disk_name.name = (unsigned char *) iname->name;
fname->disk_name.len = iname->len;

-#if IS_ENABLED(CONFIG_UNICODE)
err = ext4_fname_setup_ci_filename(dir, iname, fname);
-#endif
-
return err;
}

@@ -2826,10 +2832,7 @@ static inline int ext4_fname_prepare_lookup(struct inode *dir,

static inline void ext4_fname_free_filename(struct ext4_filename *fname)
{
-#if IS_ENABLED(CONFIG_UNICODE)
- kfree(fname->cf_name.name);
- fname->cf_name.name = NULL;
-#endif
+ ext4_fname_free_ci_filename(fname);
}
#endif /* !CONFIG_FS_ENCRYPTION */

diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 8fbb35187f72..f142c8fef750 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1755,8 +1755,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
}
}

-#if IS_ENABLED(CONFIG_UNICODE)
- if (!inode && IS_CASEFOLDED(dir)) {
+ if (IS_ENABLED(CONFIG_UNICODE) && !inode && IS_CASEFOLDED(dir)) {
/* Eventually we want to call d_add_ci(dentry, NULL)
* for negative dentries in the encoding case as
* well. For now, prevent the negative dentry
@@ -1764,7 +1763,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
*/
return NULL;
}
-#endif
+
return d_splice_alias(inode, dentry);
}

@@ -3081,16 +3080,14 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
ext4_fc_track_unlink(handle, dentry);
retval = ext4_mark_inode_dirty(handle, dir);

-#if IS_ENABLED(CONFIG_UNICODE)
/* VFS negative dentries are incompatible with Encoding and
* Case-insensitiveness. Eventually we'll want avoid
* invalidating the dentries here, alongside with returning the
* negative dentries at ext4_lookup(), when it is better
* supported by the VFS for the CI case.
*/
- if (IS_CASEFOLDED(dir))
+ if (IS_ENABLED(CONFIG_UNICODE) && IS_CASEFOLDED(dir))
d_invalidate(dentry);
-#endif

end_rmdir:
brelse(bh);
@@ -3186,16 +3183,16 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
retval = __ext4_unlink(handle, dir, &dentry->d_name, d_inode(dentry));
if (!retval)
ext4_fc_track_unlink(handle, dentry);
-#if IS_ENABLED(CONFIG_UNICODE)
+
/* VFS negative dentries are incompatible with Encoding and
* Case-insensitiveness. Eventually we'll want avoid
* invalidating the dentries here, alongside with returning the
* negative dentries at ext4_lookup(), when it is better
* supported by the VFS for the CI case.
*/
- if (IS_CASEFOLDED(dir))
+ if (IS_ENABLED(CONFIG_UNICODE) && IS_CASEFOLDED(dir))
d_invalidate(dentry);
-#endif
+
if (handle)
ext4_journal_stop(handle);

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 1847b46af808..fa0004459dd6 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3645,14 +3645,12 @@ int ext4_feature_set_ok(struct super_block *sb, int readonly)
return 0;
}

-#if !IS_ENABLED(CONFIG_UNICODE)
- if (ext4_has_feature_casefold(sb)) {
+ if (!IS_ENABLED(CONFIG_UNICODE) && ext4_has_feature_casefold(sb)) {
ext4_msg(sb, KERN_ERR,
"Filesystem with casefold feature cannot be "
"mounted without CONFIG_UNICODE");
return 0;
}
-#endif

if (readonly)
return 1;
--
2.36.1


2022-05-18 17:25:19

by Gabriel Krisman Bertazi

[permalink] [raw]
Subject: [PATCH v5 8/8] f2fs: Move CONFIG_UNICODE defguards into the code flow

Instead of a bunch of ifdefs, make the unicode built checks part of the
code flow where possible, as requested by Torvalds.

Signed-off-by: Gabriel Krisman Bertazi <[email protected]>

---
Changes since v4:
- Drop stub removal for !CONFIG_UNICODE case (eric)
---
fs/f2fs/namei.c | 11 +++++------
fs/f2fs/super.c | 8 ++++----
2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 5f213f05556d..8567a9045df1 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -561,8 +561,7 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
goto out_iput;
}
out_splice:
-#if IS_ENABLED(CONFIG_UNICODE)
- if (!inode && IS_CASEFOLDED(dir)) {
+ if (IS_ENABLED(CONFIG_UNICODE) && !inode && IS_CASEFOLDED(dir)) {
/* Eventually we want to call d_add_ci(dentry, NULL)
* for negative dentries in the encoding case as
* well. For now, prevent the negative dentry
@@ -571,7 +570,7 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
trace_f2fs_lookup_end(dir, dentry, ino, err);
return NULL;
}
-#endif
+
new = d_splice_alias(inode, dentry);
err = PTR_ERR_OR_ZERO(new);
trace_f2fs_lookup_end(dir, dentry, ino, !new ? -ENOENT : err);
@@ -622,16 +621,16 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
goto fail;
}
f2fs_delete_entry(de, page, dir, inode);
-#if IS_ENABLED(CONFIG_UNICODE)
+
/* VFS negative dentries are incompatible with Encoding and
* Case-insensitiveness. Eventually we'll want avoid
* invalidating the dentries here, alongside with returning the
* negative dentries at f2fs_lookup(), when it is better
* supported by the VFS for the CI case.
*/
- if (IS_CASEFOLDED(dir))
+ if (IS_ENABLED(CONFIG_UNICODE) && IS_CASEFOLDED(dir))
d_invalidate(dentry);
-#endif
+
f2fs_unlock_op(sbi);

if (IS_DIRSYNC(dir))
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index baefd398ec1a..b17bd7a70d53 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -283,7 +283,7 @@ struct kmem_cache *f2fs_cf_name_slab;
static int __init f2fs_create_casefold_cache(void)
{
f2fs_cf_name_slab = f2fs_kmem_cache_create("f2fs_casefolded_name",
- F2FS_NAME_LEN);
+ F2FS_NAME_LEN);
if (!f2fs_cf_name_slab)
return -ENOMEM;
return 0;
@@ -1259,13 +1259,13 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
return -EINVAL;
}
#endif
-#if !IS_ENABLED(CONFIG_UNICODE)
- if (f2fs_sb_has_casefold(sbi)) {
+
+ if (!IS_ENABLED(CONFIG_UNICODE) && f2fs_sb_has_casefold(sbi)) {
f2fs_err(sbi,
"Filesystem with casefold feature cannot be mounted without CONFIG_UNICODE");
return -EINVAL;
}
-#endif
+
/*
* The BLKZONED feature indicates that the drive was formatted with
* zone alignment optimization. This is optional for host-aware
--
2.36.1


2022-05-18 18:50:00

by Eric Biggers

[permalink] [raw]
Subject: Re: [PATCH v5 1/8] ext4: Simplify the handling of cached insensitive names

On Wed, May 18, 2022 at 01:23:13PM -0400, Gabriel Krisman Bertazi wrote:
> Keeping it as qstr avoids the unnecessary conversion in ext4_match
>
> Signed-off-by: Gabriel Krisman Bertazi <[email protected]>
>
> --
> Changes since v1:
> - Simplify hunk (eric)
> ---

The changelog needs to be deleted (or moved below the scissors line).

Otherwise this patch looks good:

Reviewed-by: Eric Biggers <[email protected]>

- Eric

2022-05-18 18:55:10

by Eric Biggers

[permalink] [raw]
Subject: Re: [PATCH v5 2/8] f2fs: Simplify the handling of cached insensitive names

On Wed, May 18, 2022 at 01:23:14PM -0400, Gabriel Krisman Bertazi wrote:
> Keeping it as qstr avoids the unnecessary conversion in f2fs_match
>
> Signed-off-by: Gabriel Krisman Bertazi <[email protected]>
>

Reviewed-by: Eric Biggers <[email protected]>

- Eric

2022-05-18 19:05:40

by Eric Biggers

[permalink] [raw]
Subject: Re: [PATCH v5 3/8] libfs: Introduce case-insensitive string comparison helper

On Wed, May 18, 2022 at 01:23:15PM -0400, Gabriel Krisman Bertazi wrote:
> generic_ci_match can be used by case-insensitive filesystems to compare
> strings under lookup with dirents in a case-insensitive way. This
> function is currently reimplemented by each filesystem supporting
> casefolding, so this reduces code duplication in filesystem-specific
> code.
>
> Signed-off-by: Gabriel Krisman Bertazi <[email protected]>
> ---
> fs/libfs.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/fs.h | 4 +++
> 2 files changed, 69 insertions(+)
>
> diff --git a/fs/libfs.c b/fs/libfs.c
> index 974125270a42..6861d43563be 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -1465,6 +1465,71 @@ static const struct dentry_operations generic_ci_dentry_ops = {
> .d_hash = generic_ci_d_hash,
> .d_compare = generic_ci_d_compare,
> };
> +
> +/**
> + * generic_ci_match() - Match a name (case-insensitively) name with a dirent.
> + * @parent: Inode of the parent of the dirent under comparison
> + * @name: name under lookup.
> + * @folded_name: Optional pre-folded name under lookup
> + * @de_name: Dirent name.
> + * @de_name_len: dirent name length.
> + *
> + *
> + * Test whether a case-insensitive directory entry matches the filename
> + * being searched. If @folded_name is provided, it is used instead of
> + * recalculating the casefold of @name.
> + *
> + * Return: > 0 if the directory entry matches, 0 if it doesn't match, or
> + * < 0 on error.
> + */
> +int generic_ci_match(const struct inode *parent,
> + const struct qstr *name,
> + const struct qstr *folded_name,
> + const u8 *de_name, size_t de_name_len)
> +{
> + const struct super_block *sb = parent->i_sb;
> + const struct unicode_map *um = sb->s_encoding;
> + struct fscrypt_str decrypted_name = FSTR_INIT(NULL, de_name_len);

de_name_len is getting truncated to u32, so the parameter itself should be a
u32, like f2fs_match_ci_name().

> + struct qstr dirent = QSTR_INIT(de_name, de_name_len);
> + int err, match = false;
> +
> + if (IS_ENCRYPTED(parent)) {
> + const struct fscrypt_str encrypted_name =
> + FSTR_INIT((u8 *) de_name, de_name_len);

The 'if (WARN_ON_ONCE(!fscrypt_has_encryption_key(parent))) return -EINVAL;'
from f2fs_match_ci_name() should be kept here, as this is not going to work as
intended if the encryption key is unavailable. (Unless the name is "." or "..",
as you saw in my recent patch, but that should be avoided anyway.)

> +
> + decrypted_name.name = kmalloc(de_name_len, GFP_KERNEL);
> + if (!decrypted_name.name)
> + return -ENOMEM;
> + err = fscrypt_fname_disk_to_usr(parent, 0, 0, &encrypted_name,
> + &decrypted_name);
> + if (err < 0)
> + goto out;
> + dirent.name = decrypted_name.name;
> + dirent.len = decrypted_name.len;
> + }
> +
> + if (folded_name->name)
> + err = utf8_strncasecmp_folded(um, folded_name, &dirent);
> + else
> + err = utf8_strncasecmp(um, name, &dirent);

Variables called 'err' conventionally store either 0 or a negative error value.
Here, 'err' can store a positive value. It would be better to call it something
else, such as 'res' which f2fs_match_ci_name() uses.

- Eric

2022-05-18 19:23:39

by Eric Biggers

[permalink] [raw]
Subject: Re: [PATCH v5 5/8] f2fs: Reuse generic_ci_match for ci comparisons

On Wed, May 18, 2022 at 01:23:17PM -0400, Gabriel Krisman Bertazi wrote:
> @@ -277,8 +225,10 @@ static inline int f2fs_match_name(const struct inode *dir,
>
> #if IS_ENABLED(CONFIG_UNICODE)
> if (fname->cf_name.name)
> - return f2fs_match_ci_name(dir, &fname->cf_name,
> - de_name, de_name_len);
> + return generic_ci_match(dir, fname->usr_fname,
> + &fname->cf_name,
> + (u8 *) de_name, de_name_len);
> +

There's no need for the cast to '(u8 *)'.

- Eric

2022-05-18 19:23:39

by Eric Biggers

[permalink] [raw]
Subject: Re: [PATCH v5 4/8] ext4: Reuse generic_ci_match for ci comparisons

On Wed, May 18, 2022 at 01:23:16PM -0400, Gabriel Krisman Bertazi wrote:
> Instead of reimplementing ext4_match_ci, use the new libfs helper.
>
> Signed-off-by: Gabriel Krisman Bertazi <[email protected]>
> ---
[...]
> int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
> struct ext4_filename *name)
> {
> @@ -1432,20 +1380,25 @@ static bool ext4_match(struct inode *parent,
> #if IS_ENABLED(CONFIG_UNICODE)
> if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent) &&
> (!IS_ENCRYPTED(parent) || fscrypt_has_encryption_key(parent))) {
> - if (fname->cf_name.name) {
> - if (IS_ENCRYPTED(parent)) {
> - if (fname->hinfo.hash != EXT4_DIRENT_HASH(de) ||
> - fname->hinfo.minor_hash !=
> - EXT4_DIRENT_MINOR_HASH(de)) {
> + int ret;
>
> - return false;
> - }
> - }
> - return !ext4_ci_compare(parent, &fname->cf_name,
> - de->name, de->name_len, true);
> + if (IS_ENCRYPTED(parent) &&
> + (fname->hinfo.hash != EXT4_DIRENT_HASH(de) ||
> + fname->hinfo.minor_hash != EXT4_DIRENT_MINOR_HASH(de)))
> + return false;
> +
> + ret = generic_ci_match(parent, fname->usr_fname,
> + &fname->cf_name, de->name,
> + de->name_len);
> + if (ret < 0) {
> + /*
> + * Treat comparison errors as not a match. The
> + * only case where it happens is on a disk
> + * corruption or ENOMEM.
> + */
> + return false;
> }
> - return !ext4_ci_compare(parent, fname->usr_fname, de->name,
> - de->name_len, false);
> + return ret;
> }

This needs an explanation for why it's okay to remove
'fname->cf_name.name != NULL' from the condition for doing the hash comparison
for an encrypted+casefolded directory entry.

- Eric

2022-05-18 19:23:39

by Eric Biggers

[permalink] [raw]
Subject: Re: [PATCH v5 6/8] ext4: Log error when lookup of encoded dentry fails

On Wed, May 18, 2022 at 01:23:18PM -0400, Gabriel Krisman Bertazi wrote:
> If the volume is in strict mode, ext4_ci_compare can report a broken
> encoding name. This will not trigger on a bad lookup, which is caught
> earlier, only if the actual disk name is bad.
>
> Signed-off-by: Gabriel Krisman Bertazi <[email protected]>
>
> ---
>
> changes since v4:
> - Reword error message (Eric)
>
> Changes since v1:
> - reword error message "file in directory" -> "filename" (Eric)
> ---
> fs/ext4/namei.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
> index 98295b03a57c..8fbb35187f72 100644
> --- a/fs/ext4/namei.c
> +++ b/fs/ext4/namei.c
> @@ -1396,6 +1396,9 @@ static bool ext4_match(struct inode *parent,
> * only case where it happens is on a disk
> * corruption or ENOMEM.
> */
> + if (ret == -EINVAL)
> + EXT4_ERROR_INODE(parent,
> + "Directory contains filename that is invalid UTF-8");
> return false;
> }
> return ret;

Reviewed-by: Eric Biggers <[email protected]>

- Eric

2022-05-18 19:29:25

by Eric Biggers

[permalink] [raw]
Subject: Re: [PATCH v5 7/8] ext4: Move CONFIG_UNICODE defguards into the code flow

On Wed, May 18, 2022 at 01:23:19PM -0400, Gabriel Krisman Bertazi wrote:
> Instead of a bunch of ifdefs, make the unicode built checks part of the
> code flow where possible, as requested by Torvalds.
>
> Signed-off-by: Gabriel Krisman Bertazi <[email protected]>
>
> ---
> Changes since v4:
> - Create stub for !CONFIG_UNICODE case (eric)
> ---
> fs/ext4/ext4.h | 37 ++++++++++++++++++++-----------------
> fs/ext4/namei.c | 15 ++++++---------
> fs/ext4/super.c | 4 +---
> 3 files changed, 27 insertions(+), 29 deletions(-)
>
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index 93a28fcb2e22..c38999ee3627 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -2727,8 +2727,24 @@ ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
>
> #if IS_ENABLED(CONFIG_UNICODE)
> extern int ext4_fname_setup_ci_filename(struct inode *dir,
> - const struct qstr *iname,
> - struct ext4_filename *fname);
> + const struct qstr *iname,
> + struct ext4_filename *fname);
> +
> +static inline void ext4_fname_free_ci_filename(struct ext4_filename *fname)
> +{
> + kfree(fname->cf_name.name);
> + fname->cf_name.name = NULL;
> +}
> +#else
> +static inline int ext4_fname_setup_ci_filename(struct inode *dir,
> + const struct qstr *iname,
> + struct ext4_filename *fname)
> +{
> + return 0;
> +}
> +static inline void ext4_fname_free_ci_filename(struct ext4_filename *fname)
> +{
> +}
> #endif
>
> #ifdef CONFIG_FS_ENCRYPTION
> @@ -2758,9 +2774,7 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
>
> ext4_fname_from_fscrypt_name(fname, &name);
>
> -#if IS_ENABLED(CONFIG_UNICODE)
> err = ext4_fname_setup_ci_filename(dir, iname, fname);
> -#endif
> return err;
> }

This can just do 'return ext4_fname_setup_ci_filename(...)'. No need for the
err variable.

>
> @@ -2777,9 +2791,7 @@ static inline int ext4_fname_prepare_lookup(struct inode *dir,
>
> ext4_fname_from_fscrypt_name(fname, &name);
>
> -#if IS_ENABLED(CONFIG_UNICODE)
> err = ext4_fname_setup_ci_filename(dir, &dentry->d_name, fname);
> -#endif
> return err;
> }

Similarly, this can just return ext4_fname_setup_ci_filename(...).

>
> @@ -2794,10 +2806,7 @@ static inline void ext4_fname_free_filename(struct ext4_filename *fname)
> fname->usr_fname = NULL;
> fname->disk_name.name = NULL;
>
> -#if IS_ENABLED(CONFIG_UNICODE)
> - kfree(fname->cf_name.name);
> - fname->cf_name.name = NULL;
> -#endif
> + ext4_fname_free_ci_filename(fname);
> }
> #else /* !CONFIG_FS_ENCRYPTION */
> static inline int ext4_fname_setup_filename(struct inode *dir,
> @@ -2810,10 +2819,7 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
> fname->disk_name.name = (unsigned char *) iname->name;
> fname->disk_name.len = iname->len;
>
> -#if IS_ENABLED(CONFIG_UNICODE)
> err = ext4_fname_setup_ci_filename(dir, iname, fname);
> -#endif
> -
> return err;

Likewise.

- Eric

2022-05-18 19:29:28

by Eric Biggers

[permalink] [raw]
Subject: Re: [PATCH v5 8/8] f2fs: Move CONFIG_UNICODE defguards into the code flow

On Wed, May 18, 2022 at 01:23:20PM -0400, Gabriel Krisman Bertazi wrote:
> Instead of a bunch of ifdefs, make the unicode built checks part of the
> code flow where possible, as requested by Torvalds.
>
> Signed-off-by: Gabriel Krisman Bertazi <[email protected]>
>
> ---
> Changes since v4:
> - Drop stub removal for !CONFIG_UNICODE case (eric)
> ---
> fs/f2fs/namei.c | 11 +++++------
> fs/f2fs/super.c | 8 ++++----
> 2 files changed, 9 insertions(+), 10 deletions(-)

Reviewed-by: Eric Biggers <[email protected]>

- Eric

2022-05-18 22:48:28

by Gabriel Krisman Bertazi

[permalink] [raw]
Subject: Re: [PATCH v5 4/8] ext4: Reuse generic_ci_match for ci comparisons

Eric Biggers <[email protected]> writes:

> On Wed, May 18, 2022 at 01:23:16PM -0400, Gabriel Krisman Bertazi wrote:
>> Instead of reimplementing ext4_match_ci, use the new libfs helper.
>>
>> Signed-off-by: Gabriel Krisman Bertazi <[email protected]>
>> ---
> [...]
>> int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
>> struct ext4_filename *name)
>> {
>> @@ -1432,20 +1380,25 @@ static bool ext4_match(struct inode *parent,
>> #if IS_ENABLED(CONFIG_UNICODE)
>> if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent) &&
>> (!IS_ENCRYPTED(parent) || fscrypt_has_encryption_key(parent))) {
>> - if (fname->cf_name.name) {
>> - if (IS_ENCRYPTED(parent)) {
>> - if (fname->hinfo.hash != EXT4_DIRENT_HASH(de) ||
>> - fname->hinfo.minor_hash !=
>> - EXT4_DIRENT_MINOR_HASH(de)) {
>> + int ret;
>>
>> - return false;
>> - }
>> - }
>> - return !ext4_ci_compare(parent, &fname->cf_name,
>> - de->name, de->name_len, true);
>> + if (IS_ENCRYPTED(parent) &&
>> + (fname->hinfo.hash != EXT4_DIRENT_HASH(de) ||
>> + fname->hinfo.minor_hash != EXT4_DIRENT_MINOR_HASH(de)))
>> + return false;
>> +
>> + ret = generic_ci_match(parent, fname->usr_fname,
>> + &fname->cf_name, de->name,
>> + de->name_len);
>> + if (ret < 0) {
>> + /*
>> + * Treat comparison errors as not a match. The
>> + * only case where it happens is on a disk
>> + * corruption or ENOMEM.
>> + */
>> + return false;
>> }
>> - return !ext4_ci_compare(parent, fname->usr_fname, de->name,
>> - de->name_len, false);
>> + return ret;
>> }
>
> This needs an explanation for why it's okay to remove
> 'fname->cf_name.name != NULL' from the condition for doing the hash comparison
> for an encrypted+casefolded directory entry.

Hi Eric,

The reason is that the only two ways for fname->cf_name to be NULL on a
case-insensitive lookup is 1) if name under lookup has an invalid
encoding and the FS is not in strict mode; or 2) if the directory is
encrypted and we don't have the key. For case 1, it doesn't
matter, because the lookup hash will be generated with fname->usr_name,
the same as the disk (fallback to invalid encoding behavior on !strict
mode). Case 2 is caught by the previous check
(!IS_ENCRYPTED(parent) || fscrypt_has_encryption_key(parent)), so we
never reach this code.

I'll add the above rationale to the commit message.

--
Gabriel Krisman Bertazi

2022-05-19 13:16:37

by Chao Yu

[permalink] [raw]
Subject: Re: [f2fs-dev] [PATCH v5 2/8] f2fs: Simplify the handling of cached insensitive names

On 2022/5/19 1:23, Gabriel Krisman Bertazi wrote:
> Keeping it as qstr avoids the unnecessary conversion in f2fs_match
>
> Signed-off-by: Gabriel Krisman Bertazi <[email protected]>

Reviewed-by: Chao Yu <[email protected]>

Thanks,

2022-05-19 19:02:04

by Chao Yu

[permalink] [raw]
Subject: Re: [f2fs-dev] [PATCH v5 2/8] f2fs: Simplify the handling of cached insensitive names

On 2022/5/19 19:27, Chao Yu wrote:
> On 2022/5/19 1:23, Gabriel Krisman Bertazi wrote:
>> Keeping it as qstr avoids the unnecessary conversion in f2fs_match
>>
>> Signed-off-by: Gabriel Krisman Bertazi <[email protected]>
>
> Reviewed-by: Chao Yu <[email protected]>

Oh, this should be replied to v6, sorry.

Thanks,

>
> Thanks,
>
>
> _______________________________________________
> Linux-f2fs-devel mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel