public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/6] exfat: unify FAT chain walking helpers
@ 2026-04-03  8:05 ` Chi Zhiling
  2026-04-03  8:05   ` [PATCH v3 1/6] exfat: fix incorrect directory checksum after rename to shorter name Chi Zhiling
                     ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Chi Zhiling @ 2026-04-03  8:05 UTC (permalink / raw)
  To: Namjae Jeon, Sungjong Seo, Yuezhang Mo
  Cc: linux-fsdevel, linux-kernel, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

This series introduces and uses two new helpers to simplify FAT chain
walking logic across the exfat driver:

1. exfat_fat_walk - walks FAT chain by a given step, handling both
   ALLOC_NO_FAT_CHAIN and ALLOC_FAT_CHAIN modes

2. exfat_chain_advance - walks an exfat_chain structure by a given step,
   updating both ->dir and ->size fields atomically with proper boundary
   checking

These helpers replace open-coded cluster walking logic in dir.c, namei.c
and inode.c, improving code readability and ensuring consistent error
handling for corrupted FAT chains.

Also includes a fix for incorrect directory checksum when renaming a
file to a shorter name.

---

Changes in v3:
- rework exfat_chain_advance
- add error handling in exfat_find_location
- misc tweaks

v1:https://lore.kernel.org/linux-fsdevel/20260331091113.20882-1-chizhiling@163.com/
v2:https://lore.kernel.org/linux-fsdevel/20260401071138.114836-1-chizhiling@163.com/


Chi Zhiling (6):
  exfat: fix incorrect directory checksum after rename to shorter name
  exfat: introduce exfat_cluster_walk helper
  exfat: use exfat_cluster_walk helper
  exfat: remove NULL cache pointer case in exfat_ent_get
  exfat: introduce exfat_chain_advance helper
  exfat: use exfat_chain_advance helper

 fs/exfat/dir.c      | 119 +++++++++++---------------------------------
 fs/exfat/exfat_fs.h |  44 +++++++++++++++-
 fs/exfat/fatent.c   |  23 ++++-----
 fs/exfat/inode.c    |  11 +---
 fs/exfat/namei.c    |  28 +++--------
 5 files changed, 91 insertions(+), 134 deletions(-)


base-commit: 4129a3a2751cba8511cee5d13145223662a8e019
-- 
2.43.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3 1/6] exfat: fix incorrect directory checksum after rename to shorter name
  2026-04-03  8:05 ` [PATCH v3 0/6] exfat: unify FAT chain walking helpers Chi Zhiling
@ 2026-04-03  8:05   ` Chi Zhiling
  2026-04-03  8:05   ` [PATCH v3 2/6] exfat: introduce exfat_cluster_walk helper Chi Zhiling
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Chi Zhiling @ 2026-04-03  8:05 UTC (permalink / raw)
  To: Namjae Jeon, Sungjong Seo, Yuezhang Mo
  Cc: linux-fsdevel, linux-kernel, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

When renaming a file in-place to a shorter name, exfat_remove_entries
marks excess entries as DELETED, but es->num_entries is not updated
accordingly. As a result, exfat_update_dir_chksum iterates over the
deleted entries and computes an incorrect checksum.

This does not lead to persistent corruption because mark_inode_dirty()
is called afterward, and __exfat_write_inode later recomputes the
checksum using the correct num_entries value.

Fix by setting es->num_entries = num_entries in exfat_init_ext_entry.

Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
 fs/exfat/dir.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c
index a2c2b998808c..7619410d668e 100644
--- a/fs/exfat/dir.c
+++ b/fs/exfat/dir.c
@@ -490,6 +490,7 @@ void exfat_init_ext_entry(struct exfat_entry_set_cache *es, int num_entries,
 	unsigned short *uniname = p_uniname->name;
 	struct exfat_dentry *ep;
 
+	es->num_entries = num_entries;
 	ep = exfat_get_dentry_cached(es, ES_IDX_FILE);
 	ep->dentry.file.num_ext = (unsigned char)(num_entries - 1);
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 2/6] exfat: introduce exfat_cluster_walk helper
  2026-04-03  8:05 ` [PATCH v3 0/6] exfat: unify FAT chain walking helpers Chi Zhiling
  2026-04-03  8:05   ` [PATCH v3 1/6] exfat: fix incorrect directory checksum after rename to shorter name Chi Zhiling
@ 2026-04-03  8:05   ` Chi Zhiling
  2026-04-03  8:05   ` [PATCH v3 3/6] exfat: use " Chi Zhiling
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Chi Zhiling @ 2026-04-03  8:05 UTC (permalink / raw)
  To: Namjae Jeon, Sungjong Seo, Yuezhang Mo
  Cc: linux-fsdevel, linux-kernel, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

Introduce exfat_cluster_walk() to walk the FAT chain by a given step,
handling both ALLOC_NO_FAT_CHAIN and ALLOC_FAT_CHAIN modes. Also
redefine exfat_get_next_cluster as a thin wrapper around it for
backward compatibility.

Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
 fs/exfat/exfat_fs.h | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index 9fed9fb33cae..7f9d0cfa252b 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -437,7 +437,8 @@ int exfat_set_volume_dirty(struct super_block *sb);
 int exfat_clear_volume_dirty(struct super_block *sb);
 
 /* fatent.c */
-#define exfat_get_next_cluster(sb, pclu) exfat_ent_get(sb, *(pclu), pclu, NULL)
+#define exfat_get_next_cluster(sb, pclu) \
+	exfat_cluster_walk(sb, (pclu), 1, ALLOC_FAT_CHAIN)
 
 int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
 		struct exfat_chain *p_chain, bool sync_bmap);
@@ -456,6 +457,26 @@ int exfat_count_num_clusters(struct super_block *sb,
 int exfat_blk_readahead(struct super_block *sb, sector_t sec,
 		sector_t *ra, blkcnt_t *ra_cnt, sector_t end);
 
+static inline int
+exfat_cluster_walk(struct super_block *sb, unsigned int *clu,
+		unsigned int step, int flags)
+{
+	struct buffer_head *bh = NULL;
+
+	if (flags == ALLOC_NO_FAT_CHAIN) {
+		(*clu) += step;
+		return 0;
+	}
+
+	while (step--) {
+		if (exfat_ent_get(sb, *clu, clu, &bh))
+			return -EIO;
+	}
+	brelse(bh);
+
+	return 0;
+}
+
 /* balloc.c */
 int exfat_load_bitmap(struct super_block *sb);
 void exfat_free_bitmap(struct exfat_sb_info *sbi);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 3/6] exfat: use exfat_cluster_walk helper
  2026-04-03  8:05 ` [PATCH v3 0/6] exfat: unify FAT chain walking helpers Chi Zhiling
  2026-04-03  8:05   ` [PATCH v3 1/6] exfat: fix incorrect directory checksum after rename to shorter name Chi Zhiling
  2026-04-03  8:05   ` [PATCH v3 2/6] exfat: introduce exfat_cluster_walk helper Chi Zhiling
@ 2026-04-03  8:05   ` Chi Zhiling
  2026-04-03  8:05   ` [PATCH v3 4/6] exfat: remove NULL cache pointer case in exfat_ent_get Chi Zhiling
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Chi Zhiling @ 2026-04-03  8:05 UTC (permalink / raw)
  To: Namjae Jeon, Sungjong Seo, Yuezhang Mo
  Cc: linux-fsdevel, linux-kernel, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

Replace the custom exfat_walk_fat_chain() function and open-coded
FAT chain walking logic with the exfat_cluster_walk() helper across
exfat_find_location, __exfat_get_dentry_set, and exfat_map_cluster.

Suggested-by: Sungjong Seo <sj1557.seo@samsung.com>
Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
 fs/exfat/dir.c   | 47 +++++++++++------------------------------------
 fs/exfat/inode.c | 11 ++---------
 2 files changed, 13 insertions(+), 45 deletions(-)

diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c
index 7619410d668e..ca5827046a1f 100644
--- a/fs/exfat/dir.c
+++ b/fs/exfat/dir.c
@@ -562,38 +562,6 @@ int exfat_put_dentry_set(struct exfat_entry_set_cache *es, int sync)
 	return err;
 }
 
-static int exfat_walk_fat_chain(struct super_block *sb,
-		struct exfat_chain *p_dir, unsigned int byte_offset,
-		unsigned int *clu)
-{
-	struct exfat_sb_info *sbi = EXFAT_SB(sb);
-	unsigned int clu_offset;
-	unsigned int cur_clu;
-
-	clu_offset = EXFAT_B_TO_CLU(byte_offset, sbi);
-	cur_clu = p_dir->dir;
-
-	if (p_dir->flags == ALLOC_NO_FAT_CHAIN) {
-		cur_clu += clu_offset;
-	} else {
-		while (clu_offset > 0) {
-			if (exfat_get_next_cluster(sb, &cur_clu))
-				return -EIO;
-			if (cur_clu == EXFAT_EOF_CLUSTER) {
-				exfat_fs_error(sb,
-					"invalid dentry access beyond EOF (clu : %u, eidx : %d)",
-					p_dir->dir,
-					EXFAT_B_TO_DEN(byte_offset));
-				return -EIO;
-			}
-			clu_offset--;
-		}
-	}
-
-	*clu = cur_clu;
-	return 0;
-}
-
 static int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir,
 			       int entry, sector_t *sector, int *offset)
 {
@@ -603,10 +571,19 @@ static int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir
 
 	off = EXFAT_DEN_TO_B(entry);
 
-	ret = exfat_walk_fat_chain(sb, p_dir, off, &clu);
+	clu = p_dir->dir;
+	ret = exfat_cluster_walk(sb, &clu, EXFAT_B_TO_CLU(off, sbi), p_dir->flags);
 	if (ret)
 		return ret;
 
+	if (clu == EXFAT_EOF_CLUSTER) {
+		exfat_fs_error(sb,
+			"unexpected early break in cluster chain (clu : %u, len : %d)",
+			p_dir->dir,
+			EXFAT_B_TO_CLU(off, sbi));
+		return -EIO;
+	}
+
 	if (!exfat_test_bitmap(sb, clu)) {
 		exfat_err(sb, "failed to test cluster bit(%u)", clu);
 		return -EIO;
@@ -792,9 +769,7 @@ static int __exfat_get_dentry_set(struct exfat_entry_set_cache *es,
 		if (exfat_is_last_sector_in_cluster(sbi, sec)) {
 			unsigned int clu = exfat_sector_to_cluster(sbi, sec);
 
-			if (p_dir->flags == ALLOC_NO_FAT_CHAIN)
-				clu++;
-			else if (exfat_get_next_cluster(sb, &clu))
+			if (exfat_cluster_walk(sb, &clu, 1, p_dir->flags))
 				goto put_es;
 			sec = exfat_cluster_to_sector(sbi, clu);
 		} else {
diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
index beb9ea7cca9f..cde2eb0f31ad 100644
--- a/fs/exfat/inode.c
+++ b/fs/exfat/inode.c
@@ -225,15 +225,8 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
 		 * *clu = (the first cluster of the allocated chain) =>
 		 * (the last cluster of ...)
 		 */
-		if (ei->flags == ALLOC_NO_FAT_CHAIN) {
-			*clu += num_to_be_allocated - 1;
-		} else {
-			while (num_to_be_allocated > 1) {
-				if (exfat_get_next_cluster(sb, clu))
-					return -EIO;
-				num_to_be_allocated--;
-			}
-		}
+		if (exfat_cluster_walk(sb, clu, num_to_be_allocated - 1, ei->flags))
+			return -EIO;
 		*count = 1;
 	}
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 4/6] exfat: remove NULL cache pointer case in exfat_ent_get
  2026-04-03  8:05 ` [PATCH v3 0/6] exfat: unify FAT chain walking helpers Chi Zhiling
                     ` (2 preceding siblings ...)
  2026-04-03  8:05   ` [PATCH v3 3/6] exfat: use " Chi Zhiling
@ 2026-04-03  8:05   ` Chi Zhiling
  2026-04-03  8:05   ` [PATCH v3 5/6] exfat: introduce exfat_chain_advance helper Chi Zhiling
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Chi Zhiling @ 2026-04-03  8:05 UTC (permalink / raw)
  To: Namjae Jeon, Sungjong Seo, Yuezhang Mo
  Cc: linux-fsdevel, linux-kernel, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

Since exfat_get_next_cluster has been updated, no callers pass a NULL
pointer to exfat_ent_get, so remove the handling logic for this case.

Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
 fs/exfat/fatent.c | 23 +++++++++--------------
 1 file changed, 9 insertions(+), 14 deletions(-)

diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c
index f2e5d5dde393..dce0955e689a 100644
--- a/fs/exfat/fatent.c
+++ b/fs/exfat/fatent.c
@@ -44,11 +44,11 @@ static int exfat_end_bh(struct super_block *sb, struct buffer_head *bh)
 }
 
 static int __exfat_ent_get(struct super_block *sb, unsigned int loc,
-		unsigned int *content, struct buffer_head **last)
+		unsigned int *content, struct buffer_head **cache)
 {
 	unsigned int off;
 	sector_t sec;
-	struct buffer_head *bh = last ? *last : NULL;
+	struct buffer_head *bh = *cache;
 
 	sec = FAT_ENT_OFFSET_SECTOR(sb, loc);
 	off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc);
@@ -56,8 +56,7 @@ static int __exfat_ent_get(struct super_block *sb, unsigned int loc,
 	if (!bh || bh->b_blocknr != sec || !buffer_uptodate(bh)) {
 		brelse(bh);
 		bh = sb_bread(sb, sec);
-		if (last)
-			*last = bh;
+		*cache = bh;
 		if (unlikely(!bh))
 			return -EIO;
 	}
@@ -68,8 +67,6 @@ static int __exfat_ent_get(struct super_block *sb, unsigned int loc,
 	if (*content > EXFAT_BAD_CLUSTER)
 		*content = EXFAT_EOF_CLUSTER;
 
-	if (!last)
-		brelse(bh);
 	return 0;
 }
 
@@ -111,7 +108,7 @@ int exfat_ent_set(struct super_block *sb, unsigned int loc,
  * Caller must release the buffer_head if no error return.
  */
 int exfat_ent_get(struct super_block *sb, unsigned int loc,
-		unsigned int *content, struct buffer_head **last)
+		unsigned int *content, struct buffer_head **cache)
 {
 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
 
@@ -122,7 +119,7 @@ int exfat_ent_get(struct super_block *sb, unsigned int loc,
 		goto err;
 	}
 
-	if (unlikely(__exfat_ent_get(sb, loc, content, last))) {
+	if (unlikely(__exfat_ent_get(sb, loc, content, cache))) {
 		exfat_fs_error_ratelimit(sb,
 			"failed to access to FAT (entry 0x%08x)",
 			loc);
@@ -151,13 +148,11 @@ int exfat_ent_get(struct super_block *sb, unsigned int loc,
 	}
 
 	return 0;
-err:
-	if (last) {
-		brelse(*last);
 
-		/* Avoid double release */
-		*last = NULL;
-	}
+err:
+	/* Avoid double release */
+	brelse(*cache);
+	*cache = NULL;
 	return -EIO;
 }
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 5/6] exfat: introduce exfat_chain_advance helper
  2026-04-03  8:05 ` [PATCH v3 0/6] exfat: unify FAT chain walking helpers Chi Zhiling
                     ` (3 preceding siblings ...)
  2026-04-03  8:05   ` [PATCH v3 4/6] exfat: remove NULL cache pointer case in exfat_ent_get Chi Zhiling
@ 2026-04-03  8:05   ` Chi Zhiling
  2026-04-03  8:05   ` [PATCH v3 6/6] exfat: use " Chi Zhiling
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Chi Zhiling @ 2026-04-03  8:05 UTC (permalink / raw)
  To: Namjae Jeon, Sungjong Seo, Yuezhang Mo
  Cc: linux-fsdevel, linux-kernel, Chi Zhiling, syzbot, Yuezhang Mo

From: Chi Zhiling <chizhiling@kylinos.cn>

Introduce exfat_chain_advance() to walk a exfat_chain structure by a
given step, updating both ->dir and ->size fields atomically. This
helper handles both ALLOC_NO_FAT_CHAIN and ALLOC_FAT_CHAIN modes with
proper boundary checking.

Tested-by: syzbot@syzkaller.appspotmail.com
Suggested-by: Yuezhang Mo <Yuezhang.Mo@sony.com>
Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
 fs/exfat/exfat_fs.h | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index 7f9d0cfa252b..89ef5368277f 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -552,6 +552,27 @@ int exfat_read_volume_label(struct super_block *sb,
 int exfat_write_volume_label(struct super_block *sb,
 			     struct exfat_uni_name *label);
 
+static inline int exfat_chain_advance(struct super_block *sb,
+		struct exfat_chain *chain, unsigned int step)
+{
+	unsigned int clu = chain->dir;
+
+	if (unlikely(chain->size < step))
+		return -EIO;
+
+	if (exfat_cluster_walk(sb, &clu, step, chain->flags))
+		return -EIO;
+
+	chain->size -= step;
+
+	if (chain->size == 0 && chain->flags == ALLOC_NO_FAT_CHAIN)
+		chain->dir = EXFAT_EOF_CLUSTER;
+	else
+		chain->dir = clu;
+
+	return 0;
+}
+
 /* inode.c */
 extern const struct inode_operations exfat_file_inode_operations;
 void exfat_sync_inode(struct inode *inode);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 6/6] exfat: use exfat_chain_advance helper
  2026-04-03  8:05 ` [PATCH v3 0/6] exfat: unify FAT chain walking helpers Chi Zhiling
                     ` (4 preceding siblings ...)
  2026-04-03  8:05   ` [PATCH v3 5/6] exfat: introduce exfat_chain_advance helper Chi Zhiling
@ 2026-04-03  8:05   ` Chi Zhiling
  2026-04-03  8:38   ` [PATCH v3 0/6] exfat: unify FAT chain walking helpers Sungjong Seo
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Chi Zhiling @ 2026-04-03  8:05 UTC (permalink / raw)
  To: Namjae Jeon, Sungjong Seo, Yuezhang Mo
  Cc: linux-fsdevel, linux-kernel, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

Replace open-coded cluster chain walking logic with exfat_chain_advance()
across exfat_readdir, exfat_find_dir_entry, exfat_count_dir_entries,
exfat_search_empty_slot and exfat_check_dir_empty.

Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
 fs/exfat/dir.c   | 71 ++++++++++++------------------------------------
 fs/exfat/namei.c | 28 +++++--------------
 2 files changed, 25 insertions(+), 74 deletions(-)

diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c
index ca5827046a1f..ac008ccaa97d 100644
--- a/fs/exfat/dir.c
+++ b/fs/exfat/dir.c
@@ -93,25 +93,19 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
 	clu_offset = EXFAT_DEN_TO_CLU(dentry, sbi);
 	exfat_chain_dup(&clu, &dir);
 
-	if (clu.flags == ALLOC_NO_FAT_CHAIN) {
-		clu.dir += clu_offset;
-		clu.size -= clu_offset;
-	} else {
+	if (clu.flags == ALLOC_FAT_CHAIN) {
 		/* hint_information */
 		if (clu_offset > 0 && ei->hint_bmap.off != EXFAT_EOF_CLUSTER &&
 		    ei->hint_bmap.off > 0 && clu_offset >= ei->hint_bmap.off) {
 			clu_offset -= ei->hint_bmap.off;
 			clu.dir = ei->hint_bmap.clu;
-		}
-
-		while (clu_offset > 0 && clu.dir != EXFAT_EOF_CLUSTER) {
-			if (exfat_get_next_cluster(sb, &(clu.dir)))
-				return -EIO;
-
-			clu_offset--;
+			clu.size -= ei->hint_bmap.off;
 		}
 	}
 
+	if (exfat_chain_advance(sb, &clu, clu_offset))
+		return -EIO;
+
 	while (clu.dir != EXFAT_EOF_CLUSTER && dentry < max_dentries) {
 		i = dentry & (dentries_per_clu - 1);
 
@@ -160,15 +154,8 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
 			return 0;
 		}
 
-		if (clu.flags == ALLOC_NO_FAT_CHAIN) {
-			if (--clu.size > 0)
-				clu.dir++;
-			else
-				clu.dir = EXFAT_EOF_CLUSTER;
-		} else {
-			if (exfat_get_next_cluster(sb, &(clu.dir)))
-				return -EIO;
-		}
+		if (exfat_chain_advance(sb, &clu, 1))
+			return -EIO;
 	}
 
 out:
@@ -1085,19 +1072,12 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
 			step = DIRENT_STEP_FILE;
 		}
 
-		if (clu.flags == ALLOC_NO_FAT_CHAIN) {
-			if (--clu.size > 0)
-				clu.dir++;
-			else
-				clu.dir = EXFAT_EOF_CLUSTER;
-		} else {
-			if (exfat_get_next_cluster(sb, &clu.dir))
-				return -EIO;
+		if (exfat_chain_advance(sb, &clu, 1))
+			return -EIO;
 
-			/* break if the cluster chain includes a loop */
-			if (unlikely(++clu_count > EXFAT_DATA_CLUSTER_COUNT(sbi)))
-				goto not_found;
-		}
+		/* break if the cluster chain includes a loop */
+		if (unlikely(++clu_count > EXFAT_DATA_CLUSTER_COUNT(sbi)))
+			goto not_found;
 	}
 
 not_found:
@@ -1132,14 +1112,7 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
 	if (!((dentry + 1) & (dentries_per_clu - 1))) {
 		int ret = 0;
 
-		if (clu.flags == ALLOC_NO_FAT_CHAIN) {
-			if (--clu.size > 0)
-				clu.dir++;
-			else
-				clu.dir = EXFAT_EOF_CLUSTER;
-		} else {
-			ret = exfat_get_next_cluster(sb, &clu.dir);
-		}
+		ret = exfat_chain_advance(sb, &clu, 1);
 
 		if (ret || clu.dir == EXFAT_EOF_CLUSTER) {
 			/* just initialized hint_stat */
@@ -1184,20 +1157,12 @@ int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir)
 			count++;
 		}
 
-		if (clu.flags == ALLOC_NO_FAT_CHAIN) {
-			if (--clu.size > 0)
-				clu.dir++;
-			else
-				clu.dir = EXFAT_EOF_CLUSTER;
-		} else {
-			if (exfat_get_next_cluster(sb, &(clu.dir)))
-				return -EIO;
-
-			if (unlikely(++clu_count > sbi->used_clusters)) {
-				exfat_fs_error(sb, "FAT or bitmap is corrupted");
-				return -EIO;
-			}
+		if (exfat_chain_advance(sb, &clu, 1))
+			return -EIO;
 
+		if (unlikely(++clu_count > sbi->used_clusters)) {
+			exfat_fs_error(sb, "FAT or bitmap is corrupted");
+			return -EIO;
 		}
 	}
 
diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c
index d0ea1ff81c09..2c5636634b4a 100644
--- a/fs/exfat/namei.c
+++ b/fs/exfat/namei.c
@@ -246,15 +246,8 @@ static int exfat_search_empty_slot(struct super_block *sb,
 		i += ret;
 
 		while (i >= dentries_per_clu) {
-			if (clu.flags == ALLOC_NO_FAT_CHAIN) {
-				if (--clu.size > 0)
-					clu.dir++;
-				else
-					clu.dir = EXFAT_EOF_CLUSTER;
-			} else {
-				if (exfat_get_next_cluster(sb, &clu.dir))
-					return -EIO;
-			}
+			if (exfat_chain_advance(sb, &clu, 1))
+				return -EIO;
 
 			i -= dentries_per_clu;
 		}
@@ -925,19 +918,12 @@ static int exfat_check_dir_empty(struct super_block *sb,
 			return -ENOTEMPTY;
 		}
 
-		if (clu.flags == ALLOC_NO_FAT_CHAIN) {
-			if (--clu.size > 0)
-				clu.dir++;
-			else
-				clu.dir = EXFAT_EOF_CLUSTER;
-		} else {
-			if (exfat_get_next_cluster(sb, &(clu.dir)))
-				return -EIO;
+		if (exfat_chain_advance(sb, &clu, 1))
+			return -EIO;
 
-			/* break if the cluster chain includes a loop */
-			if (unlikely(++clu_count > EXFAT_DATA_CLUSTER_COUNT(sbi)))
-				break;
-		}
+		/* break if the cluster chain includes a loop */
+		if (unlikely(++clu_count > EXFAT_DATA_CLUSTER_COUNT(sbi)))
+			break;
 	}
 
 	return 0;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* RE: [PATCH v3 0/6] exfat: unify FAT chain walking helpers
  2026-04-03  8:05 ` [PATCH v3 0/6] exfat: unify FAT chain walking helpers Chi Zhiling
                     ` (5 preceding siblings ...)
  2026-04-03  8:05   ` [PATCH v3 6/6] exfat: use " Chi Zhiling
@ 2026-04-03  8:38   ` Sungjong Seo
  2026-04-03 10:07   ` Yuezhang.Mo
  2026-04-03 13:44   ` Namjae Jeon
  8 siblings, 0 replies; 10+ messages in thread
From: Sungjong Seo @ 2026-04-03  8:38 UTC (permalink / raw)
  To: 'Chi Zhiling', 'Namjae Jeon',
	'Yuezhang Mo'
  Cc: linux-fsdevel, linux-kernel, 'Chi Zhiling', cpgs,
	sj1557.seo

> This series introduces and uses two new helpers to simplify FAT chain
> walking logic across the exfat driver:
> 
> 1. exfat_fat_walk - walks FAT chain by a given step, handling both
>    ALLOC_NO_FAT_CHAIN and ALLOC_FAT_CHAIN modes
> 
> 2. exfat_chain_advance - walks an exfat_chain structure by a given step,
>    updating both ->dir and ->size fields atomically with proper boundary
>    checking
> 
> These helpers replace open-coded cluster walking logic in dir.c, namei.c
> and inode.c, improving code readability and ensuring consistent error
> handling for corrupted FAT chains.
> 
> Also includes a fix for incorrect directory checksum when renaming a file
> to a shorter name.
> 
> ---
> 
> Changes in v3:
> - rework exfat_chain_advance
> - add error handling in exfat_find_location
> - misc tweaks

The patch-set looks good to me:
Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>

Thanks.
> 
> v1:https://lore.kernel.org/linux-fsdevel/20260331091113.20882-1-
> chizhiling@163.com/
> v2:https://lore.kernel.org/linux-fsdevel/20260401071138.114836-1-
> chizhiling@163.com/
> 
> 
> Chi Zhiling (6):
>   exfat: fix incorrect directory checksum after rename to shorter name
>   exfat: introduce exfat_cluster_walk helper
>   exfat: use exfat_cluster_walk helper
>   exfat: remove NULL cache pointer case in exfat_ent_get
>   exfat: introduce exfat_chain_advance helper
>   exfat: use exfat_chain_advance helper
> 
>  fs/exfat/dir.c      | 119 +++++++++++---------------------------------
>  fs/exfat/exfat_fs.h |  44 +++++++++++++++-
>  fs/exfat/fatent.c   |  23 ++++-----
>  fs/exfat/inode.c    |  11 +---
>  fs/exfat/namei.c    |  28 +++--------
>  5 files changed, 91 insertions(+), 134 deletions(-)
> 
> 
> base-commit: 4129a3a2751cba8511cee5d13145223662a8e019
> --
> 2.43.0




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 0/6] exfat: unify FAT chain walking helpers
  2026-04-03  8:05 ` [PATCH v3 0/6] exfat: unify FAT chain walking helpers Chi Zhiling
                     ` (6 preceding siblings ...)
  2026-04-03  8:38   ` [PATCH v3 0/6] exfat: unify FAT chain walking helpers Sungjong Seo
@ 2026-04-03 10:07   ` Yuezhang.Mo
  2026-04-03 13:44   ` Namjae Jeon
  8 siblings, 0 replies; 10+ messages in thread
From: Yuezhang.Mo @ 2026-04-03 10:07 UTC (permalink / raw)
  To: Chi Zhiling, Namjae Jeon, Sungjong Seo
  Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
	Chi Zhiling

> Changes in v3:
> - rework exfat_chain_advance
> - add error handling in exfat_find_location
> - misc tweaks

Looks good to me.
Reviewed-by: Yuezhang Mo <Yuezhang.Mo@sony.com>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 0/6] exfat: unify FAT chain walking helpers
  2026-04-03  8:05 ` [PATCH v3 0/6] exfat: unify FAT chain walking helpers Chi Zhiling
                     ` (7 preceding siblings ...)
  2026-04-03 10:07   ` Yuezhang.Mo
@ 2026-04-03 13:44   ` Namjae Jeon
  8 siblings, 0 replies; 10+ messages in thread
From: Namjae Jeon @ 2026-04-03 13:44 UTC (permalink / raw)
  To: Chi Zhiling
  Cc: Sungjong Seo, Yuezhang Mo, linux-fsdevel, linux-kernel,
	Chi Zhiling

On Fri, Apr 3, 2026 at 5:06 PM Chi Zhiling <chizhiling@163.com> wrote:
>
> From: Chi Zhiling <chizhiling@kylinos.cn>
>
> This series introduces and uses two new helpers to simplify FAT chain
> walking logic across the exfat driver:
>
> 1. exfat_fat_walk - walks FAT chain by a given step, handling both
>    ALLOC_NO_FAT_CHAIN and ALLOC_FAT_CHAIN modes
>
> 2. exfat_chain_advance - walks an exfat_chain structure by a given step,
>    updating both ->dir and ->size fields atomically with proper boundary
>    checking
>
> These helpers replace open-coded cluster walking logic in dir.c, namei.c
> and inode.c, improving code readability and ensuring consistent error
> handling for corrupted FAT chains.
>
> Also includes a fix for incorrect directory checksum when renaming a
> file to a shorter name.
>
> ---
>
> Changes in v3:
> - rework exfat_chain_advance
> - add error handling in exfat_find_location
> - misc tweaks
>
> v1:https://lore.kernel.org/linux-fsdevel/20260331091113.20882-1-chizhiling@163.com/
> v2:https://lore.kernel.org/linux-fsdevel/20260401071138.114836-1-chizhiling@163.com/
>
>
> Chi Zhiling (6):
>   exfat: fix incorrect directory checksum after rename to shorter name
>   exfat: introduce exfat_cluster_walk helper
>   exfat: use exfat_cluster_walk helper
>   exfat: remove NULL cache pointer case in exfat_ent_get
>   exfat: introduce exfat_chain_advance helper
>   exfat: use exfat_chain_advance helper
Applied them to #dev.
Thanks!

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-04-03 13:45 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <CGME20260403080638epcas1p34e96a9d3f74f963d1085f67399f51da2@epcas1p3.samsung.com>
2026-04-03  8:05 ` [PATCH v3 0/6] exfat: unify FAT chain walking helpers Chi Zhiling
2026-04-03  8:05   ` [PATCH v3 1/6] exfat: fix incorrect directory checksum after rename to shorter name Chi Zhiling
2026-04-03  8:05   ` [PATCH v3 2/6] exfat: introduce exfat_cluster_walk helper Chi Zhiling
2026-04-03  8:05   ` [PATCH v3 3/6] exfat: use " Chi Zhiling
2026-04-03  8:05   ` [PATCH v3 4/6] exfat: remove NULL cache pointer case in exfat_ent_get Chi Zhiling
2026-04-03  8:05   ` [PATCH v3 5/6] exfat: introduce exfat_chain_advance helper Chi Zhiling
2026-04-03  8:05   ` [PATCH v3 6/6] exfat: use " Chi Zhiling
2026-04-03  8:38   ` [PATCH v3 0/6] exfat: unify FAT chain walking helpers Sungjong Seo
2026-04-03 10:07   ` Yuezhang.Mo
2026-04-03 13:44   ` Namjae Jeon

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