mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC PATCH] f2fs: fold casefolded names of F2FS_NAME_LEN bytes
@ 2026-11-03  3:07 Zhan Xusheng
  0 siblings, 0 replies; only message in thread
From: Zhan Xusheng @ 2026-11-03  3:07 UTC (permalink / raw)
  To: jaegeuk, chao
  Cc: linux-f2fs-devel, linux-kernel, ebiggers, andrealmeid,
	qkrwngud825, zhanxusheng

From: Zhan Xusheng <zhanxusheng@xiaomi.com>

utf8_casefold() needs room for the terminating NUL, but
f2fs_init_casefolded_name() gives it only F2FS_NAME_LEN bytes, so a
name that folds to exactly 255 bytes is not folded. In a casefolded
directory, creating 'A' x 255 fails with EINVAL under utf8:strict.
Without strict, after creating 'A' x 255, stat of 'a' x 255 returns
ENOENT and creating it adds a second entry.

Fold into F2FS_NAME_LEN + 1 bytes. Existing entries for these names
are hashed by the name as given, so on a miss also try that hash.

Fixes: 43c780ba2624 ("f2fs: rework filename handling")
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
---
RFC because new entries for these names get a different hash on disk.
Results in a VM, with dentries dropped before each stat:

                                 'A'x255  'a'x255  'C'x255  'c'x255
  current kernel creates 'A'        ok    ENOENT
  this patch creates 'C', 'c'       ok    ENOENT     ok       ok
                                    (one 'c' entry)
  back on the current kernel        ok    ENOENT   ENOENT   ENOENT
  strict, current kernel        create 'S' x 255: EINVAL
  strict, this patch            create ok, found in both cases

Each fsck.f2fs version matches only one side. 1.16 folds into PATH_MAX
and rewrote 'A' to the folded hash, after which the current kernel
cannot find it. The dev branch rewrote 'C' to the raw hash, after
which this patch finds it only as 'C'. fsck would need to accept both
hashes for these names. Encrypted directories are not tested.

Is the second lookup acceptable? The alternative is to keep hashing
these names as given, which fixes the EINVAL but leaves them
case-sensitive.

 fs/f2fs/dir.c   | 21 ++++++++++++++++++++-
 fs/f2fs/super.c |  2 +-
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 70847313ca6a..05ae0fa2e22b 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -76,7 +76,7 @@ int f2fs_init_casefolded_name(const struct inode *dir,
 			return -ENOMEM;
 
 		len = utf8_casefold(sb->s_encoding, fname->usr_fname,
-				    buf, F2FS_NAME_LEN);
+				    buf, F2FS_NAME_LEN + 1);
 		if (len <= 0) {
 			kmem_cache_free(f2fs_cf_name_slab, buf);
 			if (sb_has_strict_encoding(sb))
@@ -359,6 +359,10 @@ struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir,
 	unsigned int max_depth;
 	unsigned int level;
 	bool use_hash = true;
+#if IS_ENABLED(CONFIG_UNICODE)
+	struct f2fs_filename raw;
+	bool raw_tried = false;
+#endif
 
 	*dentry_block = NULL;
 
@@ -389,6 +393,21 @@ struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir,
 
 out:
 #if IS_ENABLED(CONFIG_UNICODE)
+	/*
+	 * Entries for names that fold to F2FS_NAME_LEN bytes used to be
+	 * hashed by the name as given.  Try that hash too.
+	 */
+	if (!de && !IS_ERR(*dentry_block) && use_hash && !raw_tried &&
+	    IS_CASEFOLDED(dir) && fname->cf_name.name &&
+	    fname->cf_name.len == F2FS_NAME_LEN) {
+		raw = *fname;
+		raw.cf_name.name = NULL;
+		f2fs_hash_filename(dir, &raw);
+		raw.cf_name = fname->cf_name;
+		fname = &raw;
+		raw_tried = true;
+		goto start_find_entry;
+	}
 	if (f2fs_should_fallback_to_linear(dir) &&
 		IS_CASEFOLDED(dir) && !de && use_hash) {
 		use_hash = false;
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 78dbf1e92285..4172429da862 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -505,7 +505,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 + 1);
 	return f2fs_cf_name_slab ? 0 : -ENOMEM;
 }
 
-- 
2.43.0


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-11-03  3:07 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-03  3:07 [RFC PATCH] f2fs: fold casefolded names of F2FS_NAME_LEN bytes Zhan Xusheng

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®