linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters
@ 2025-11-18  8:22 Chi Zhiling
  2025-11-18  8:22 ` [RFC PATCH 1/7] exfat: add cache option for __exfat_ent_get Chi Zhiling
                   ` (7 more replies)
  0 siblings, 8 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-11-18  8:22 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Sungjong Seo, Yuezhang Mo, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

The purpose of this patchset is to prepare for adapting exfat to iomap
in the future. Currently, the main issue preventing exfat from supporting
iomap is its inability to fetch multiple contiguous clusters.

However, this patchset does not directly modify exfat_map_cluster and
exfat_get_cluster to support multi-clusters. Instead, after obtaining
the first cluster, it uses exfat_count_contig_clusters to retrieve the
subsequent contiguous clusters.

This approach is the one with the fewest changes among all the solutions
I have attempted, making the modifications easier to review.

This patchset includes two main changes: one reduces the number of sb_bread
calls when accessing adjacent clusters to save time, and the other enables
fetching multiple contiguous entries in exfat_get_blocks.

Chi Zhiling (7):
  exfat: add cache option for __exfat_ent_get
  exfat: support reuse buffer head for exfat_ent_get
  exfat: reuse cache to improve exfat_get_cluster
  exfat: improve exfat_count_num_clusters
  exfat: improve exfat_find_last_cluster
  exfat: introduce exfat_count_contig_clusters
  exfat: get mutil-clusters in exfat_get_block

 fs/exfat/cache.c    | 11 ++++--
 fs/exfat/exfat_fs.h |  6 ++-
 fs/exfat/fatent.c   | 90 ++++++++++++++++++++++++++++++++++++---------
 fs/exfat/inode.c    | 14 ++++++-
 4 files changed, 97 insertions(+), 24 deletions(-)

-- 
2.43.0


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

* [RFC PATCH 1/7] exfat: add cache option for __exfat_ent_get
  2025-11-18  8:22 [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
@ 2025-11-18  8:22 ` Chi Zhiling
  2025-11-18  8:22 ` [RFC PATCH 2/7] exfat: support reuse buffer head for exfat_ent_get Chi Zhiling
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-11-18  8:22 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Sungjong Seo, Yuezhang Mo, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

When multiple entries are obtained consecutively, these entries are mostly
stored adjacent to each other. this patch introduces a "last" parameter to
cache the last opened buffer head, and reuse it when possible, which
reduces the number of sb_bread() calls.

When the passed parameter "last" is NULL, it means cache option is
disabled, the behavior unchanged as it was.

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

diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c
index 825083634ba2..f9c5d3485865 100644
--- a/fs/exfat/fatent.c
+++ b/fs/exfat/fatent.c
@@ -36,18 +36,21 @@ static int exfat_mirror_bh(struct super_block *sb, sector_t sec,
 }
 
 static int __exfat_ent_get(struct super_block *sb, unsigned int loc,
-		unsigned int *content)
+		unsigned int *content, struct buffer_head **last)
 {
 	unsigned int off;
 	sector_t sec;
-	struct buffer_head *bh;
+	struct buffer_head *bh = last ? *last : NULL;
 
 	sec = FAT_ENT_OFFSET_SECTOR(sb, loc);
 	off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc);
 
-	bh = sb_bread(sb, sec);
-	if (!bh)
-		return -EIO;
+	if (!bh || bh->b_blocknr != sec || !buffer_uptodate(bh)) {
+		brelse(bh);
+		bh = sb_bread(sb, sec);
+		if (!bh)
+			return -EIO;
+	}
 
 	*content = le32_to_cpu(*(__le32 *)(&bh->b_data[off]));
 
@@ -55,7 +58,10 @@ static int __exfat_ent_get(struct super_block *sb, unsigned int loc,
 	if (*content > EXFAT_BAD_CLUSTER)
 		*content = EXFAT_EOF_CLUSTER;
 
-	brelse(bh);
+	if (last)
+		*last = bh;
+	else
+		brelse(bh);
 	return 0;
 }
 
@@ -95,7 +101,7 @@ int exfat_ent_get(struct super_block *sb, unsigned int loc,
 		return -EIO;
 	}
 
-	err = __exfat_ent_get(sb, loc, content);
+	err = __exfat_ent_get(sb, loc, content, NULL);
 	if (err) {
 		exfat_fs_error_ratelimit(sb,
 			"failed to access to FAT (entry 0x%08x, err:%d)",
-- 
2.43.0


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

* [RFC PATCH 2/7] exfat: support reuse buffer head for exfat_ent_get
  2025-11-18  8:22 [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
  2025-11-18  8:22 ` [RFC PATCH 1/7] exfat: add cache option for __exfat_ent_get Chi Zhiling
@ 2025-11-18  8:22 ` Chi Zhiling
  2025-11-18  8:22 ` [RFC PATCH 3/7] exfat: reuse cache to improve exfat_get_cluster Chi Zhiling
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-11-18  8:22 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Sungjong Seo, Yuezhang Mo, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

This patch is part 2 of cached buffer head for exfat_ent_get,
it introduces an argument for exfat_ent_get, and make sure this
routine releases buffer head refcount when any error return.

Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
 fs/exfat/cache.c    |  2 +-
 fs/exfat/exfat_fs.h |  4 ++--
 fs/exfat/fatent.c   | 35 +++++++++++++++++++++++------------
 3 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c
index d5ce0ae660ba..61af3fa05ab7 100644
--- a/fs/exfat/cache.c
+++ b/fs/exfat/cache.c
@@ -287,7 +287,7 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 			return -EIO;
 		}
 
-		if (exfat_ent_get(sb, *dclus, &content))
+		if (exfat_ent_get(sb, *dclus, &content, NULL))
 			return -EIO;
 
 		*last_dclus = *dclus;
diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index 329697c89d09..d52893276e9a 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -433,13 +433,13 @@ 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)
+#define exfat_get_next_cluster(sb, pclu) exfat_ent_get(sb, *(pclu), pclu, NULL)
 
 int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
 		struct exfat_chain *p_chain, bool sync_bmap);
 int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain);
 int exfat_ent_get(struct super_block *sb, unsigned int loc,
-		unsigned int *content);
+		unsigned int *content, struct buffer_head **last);
 int exfat_ent_set(struct super_block *sb, unsigned int loc,
 		unsigned int content);
 int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain,
diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c
index f9c5d3485865..a3a19c8d2e05 100644
--- a/fs/exfat/fatent.c
+++ b/fs/exfat/fatent.c
@@ -88,8 +88,11 @@ int exfat_ent_set(struct super_block *sb, unsigned int loc,
 	return 0;
 }
 
+/*
+ * Caller must release the buffer_head if no error return.
+ */
 int exfat_ent_get(struct super_block *sb, unsigned int loc,
-		unsigned int *content)
+		unsigned int *content, struct buffer_head **last)
 {
 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
 	int err;
@@ -98,39 +101,47 @@ int exfat_ent_get(struct super_block *sb, unsigned int loc,
 		exfat_fs_error_ratelimit(sb,
 			"invalid access to FAT (entry 0x%08x)",
 			loc);
-		return -EIO;
+		goto err;
 	}
 
-	err = __exfat_ent_get(sb, loc, content, NULL);
-	if (err) {
+	err = __exfat_ent_get(sb, loc, content, last);
+	if (unlikely(err)) {
 		exfat_fs_error_ratelimit(sb,
 			"failed to access to FAT (entry 0x%08x, err:%d)",
 			loc, err);
-		return err;
+		goto err;
 	}
 
-	if (*content == EXFAT_FREE_CLUSTER) {
+	if (unlikely(*content == EXFAT_FREE_CLUSTER)) {
 		exfat_fs_error_ratelimit(sb,
 			"invalid access to FAT free cluster (entry 0x%08x)",
 			loc);
-		return -EIO;
+		goto err;
 	}
 
-	if (*content == EXFAT_BAD_CLUSTER) {
+	if (unlikely(*content == EXFAT_BAD_CLUSTER)) {
 		exfat_fs_error_ratelimit(sb,
 			"invalid access to FAT bad cluster (entry 0x%08x)",
 			loc);
-		return -EIO;
+		goto err;
 	}
 
 	if (*content != EXFAT_EOF_CLUSTER && !is_valid_cluster(sbi, *content)) {
 		exfat_fs_error_ratelimit(sb,
 			"invalid access to FAT (entry 0x%08x) bogus content (0x%08x)",
 			loc, *content);
-		return -EIO;
+		goto err;
 	}
 
 	return 0;
+err:
+	if (last) {
+		brelse(*last);
+
+		/* Avoid double release */
+		*last = NULL;
+	}
+	return err;
 }
 
 int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain,
@@ -299,7 +310,7 @@ int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain,
 	do {
 		count++;
 		clu = next;
-		if (exfat_ent_get(sb, clu, &next))
+		if (exfat_ent_get(sb, clu, &next, NULL))
 			return -EIO;
 	} while (next != EXFAT_EOF_CLUSTER && count <= p_chain->size);
 
@@ -490,7 +501,7 @@ int exfat_count_num_clusters(struct super_block *sb,
 	count = 0;
 	for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; i++) {
 		count++;
-		if (exfat_ent_get(sb, clu, &clu))
+		if (exfat_ent_get(sb, clu, &clu, NULL))
 			return -EIO;
 		if (clu == EXFAT_EOF_CLUSTER)
 			break;
-- 
2.43.0


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

* [RFC PATCH 3/7] exfat: reuse cache to improve exfat_get_cluster
  2025-11-18  8:22 [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
  2025-11-18  8:22 ` [RFC PATCH 1/7] exfat: add cache option for __exfat_ent_get Chi Zhiling
  2025-11-18  8:22 ` [RFC PATCH 2/7] exfat: support reuse buffer head for exfat_ent_get Chi Zhiling
@ 2025-11-18  8:22 ` Chi Zhiling
  2025-11-18  8:22 ` [RFC PATCH 4/7] exfat: improve exfat_count_num_clusters Chi Zhiling
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-11-18  8:22 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Sungjong Seo, Yuezhang Mo, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

Since exfat_ent_get supports cache buffer head, we can use this option to
reduce sb_bread calls when fetching consecutive entries.

Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
 fs/exfat/cache.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c
index 61af3fa05ab7..a5e6858e5a20 100644
--- a/fs/exfat/cache.c
+++ b/fs/exfat/cache.c
@@ -241,6 +241,7 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
 	unsigned int limit = sbi->num_clusters;
 	struct exfat_inode_info *ei = EXFAT_I(inode);
+	struct buffer_head *bh = NULL;
 	struct exfat_cache_id cid;
 	unsigned int content;
 
@@ -284,10 +285,10 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 			exfat_fs_error(sb,
 				"detected the cluster chain loop (i_pos %u)",
 				(*fclus));
-			return -EIO;
+			goto err;
 		}
 
-		if (exfat_ent_get(sb, *dclus, &content, NULL))
+		if (exfat_ent_get(sb, *dclus, &content, &bh))
 			return -EIO;
 
 		*last_dclus = *dclus;
@@ -299,7 +300,7 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 				exfat_fs_error(sb,
 				       "invalid cluster chain (i_pos %u, last_clus 0x%08x is EOF)",
 				       *fclus, (*last_dclus));
-				return -EIO;
+				goto err;
 			}
 
 			break;
@@ -309,6 +310,10 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 			cache_init(&cid, *fclus, *dclus);
 	}
 
+	brelse(bh);
 	exfat_cache_add(inode, &cid);
 	return 0;
+err:
+	brelse(bh);
+	return -EIO;
 }
-- 
2.43.0


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

* [RFC PATCH 4/7] exfat: improve exfat_count_num_clusters
  2025-11-18  8:22 [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
                   ` (2 preceding siblings ...)
  2025-11-18  8:22 ` [RFC PATCH 3/7] exfat: reuse cache to improve exfat_get_cluster Chi Zhiling
@ 2025-11-18  8:22 ` Chi Zhiling
  2025-11-18  8:22 ` [RFC PATCH 5/7] exfat: improve exfat_find_last_cluster Chi Zhiling
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-11-18  8:22 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Sungjong Seo, Yuezhang Mo, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

Since exfat_ent_get support cache buffer head, let's apply it to
exfat_count_num_clusters.

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

diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c
index a3a19c8d2e05..08f9a817af28 100644
--- a/fs/exfat/fatent.c
+++ b/fs/exfat/fatent.c
@@ -486,6 +486,7 @@ int exfat_count_num_clusters(struct super_block *sb,
 	unsigned int i, count;
 	unsigned int clu;
 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
+	struct buffer_head *bh = NULL;
 
 	if (!p_chain->dir || p_chain->dir == EXFAT_EOF_CLUSTER) {
 		*ret_count = 0;
@@ -501,12 +502,13 @@ int exfat_count_num_clusters(struct super_block *sb,
 	count = 0;
 	for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; i++) {
 		count++;
-		if (exfat_ent_get(sb, clu, &clu, NULL))
+		if (exfat_ent_get(sb, clu, &clu, &bh))
 			return -EIO;
 		if (clu == EXFAT_EOF_CLUSTER)
 			break;
 	}
 
+	brelse(bh);
 	*ret_count = count;
 
 	/*
-- 
2.43.0


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

* [RFC PATCH 5/7] exfat: improve exfat_find_last_cluster
  2025-11-18  8:22 [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
                   ` (3 preceding siblings ...)
  2025-11-18  8:22 ` [RFC PATCH 4/7] exfat: improve exfat_count_num_clusters Chi Zhiling
@ 2025-11-18  8:22 ` Chi Zhiling
  2025-11-18  8:22 ` [RFC PATCH 6/7] exfat: introduce exfat_count_contig_clusters Chi Zhiling
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-11-18  8:22 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Sungjong Seo, Yuezhang Mo, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

Since exfat_ent_get support cache buffer head, let's apply it to
exfat_find_last_cluster.

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

diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c
index 08f9a817af28..d980d17176c2 100644
--- a/fs/exfat/fatent.c
+++ b/fs/exfat/fatent.c
@@ -298,6 +298,7 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
 int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain,
 		unsigned int *ret_clu)
 {
+	struct buffer_head *bh = NULL;
 	unsigned int clu, next;
 	unsigned int count = 0;
 
@@ -310,10 +311,11 @@ int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain,
 	do {
 		count++;
 		clu = next;
-		if (exfat_ent_get(sb, clu, &next, NULL))
+		if (exfat_ent_get(sb, clu, &next, &bh))
 			return -EIO;
 	} while (next != EXFAT_EOF_CLUSTER && count <= p_chain->size);
 
+	brelse(bh);
 	if (p_chain->size != count) {
 		exfat_fs_error(sb,
 			"bogus directory size (clus : ondisk(%d) != counted(%d))",
-- 
2.43.0


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

* [RFC PATCH 6/7] exfat: introduce exfat_count_contig_clusters
  2025-11-18  8:22 [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
                   ` (4 preceding siblings ...)
  2025-11-18  8:22 ` [RFC PATCH 5/7] exfat: improve exfat_find_last_cluster Chi Zhiling
@ 2025-11-18  8:22 ` Chi Zhiling
  2025-11-28 11:09   ` Yuezhang.Mo
  2025-11-18  8:22 ` [RFC PATCH 7/7] exfat: get mutil-clusters in exfat_get_block Chi Zhiling
  2025-11-21  1:17 ` [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters Namjae Jeon
  7 siblings, 1 reply; 16+ messages in thread
From: Chi Zhiling @ 2025-11-18  8:22 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Sungjong Seo, Yuezhang Mo, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

This patch introduces exfat_count_contig_clusters to obtain batch entries,
which is an infrastructure used to support iomap.

Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
 fs/exfat/exfat_fs.h |  2 ++
 fs/exfat/fatent.c   | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index d52893276e9a..421dd7c61cca 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -449,6 +449,8 @@ int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain,
 		unsigned int *ret_clu);
 int exfat_count_num_clusters(struct super_block *sb,
 		struct exfat_chain *p_chain, unsigned int *ret_count);
+int exfat_count_contig_clusters(struct super_block *sb,
+		struct exfat_chain *p_chain, unsigned int *ret_count);
 
 /* balloc.c */
 int exfat_load_bitmap(struct super_block *sb);
diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c
index d980d17176c2..9dcee9524155 100644
--- a/fs/exfat/fatent.c
+++ b/fs/exfat/fatent.c
@@ -524,3 +524,36 @@ int exfat_count_num_clusters(struct super_block *sb,
 
 	return 0;
 }
+
+int exfat_count_contig_clusters(struct super_block *sb,
+		struct exfat_chain *p_chain, unsigned int *ret_count)
+{
+	struct buffer_head *bh = NULL;
+	unsigned int clu, next_clu;
+	unsigned int count;
+
+	if (!p_chain->dir || p_chain->dir == EXFAT_EOF_CLUSTER) {
+		*ret_count = 0;
+		return 0;
+	}
+
+	if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
+		*ret_count = p_chain->size;
+		return 0;
+	}
+
+	clu = p_chain->dir;
+	for (count = 1; count < p_chain->size; count++) {
+		if (exfat_ent_get(sb, clu, &next_clu, &bh))
+			return -EIO;
+		if (++clu != next_clu)
+			break;
+	}
+
+	/* TODO: Update p_claim to help caller read ahead the next block */
+
+	brelse(bh);
+	*ret_count = count;
+
+	return 0;
+}
-- 
2.43.0


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

* [RFC PATCH 7/7] exfat: get mutil-clusters in exfat_get_block
  2025-11-18  8:22 [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
                   ` (5 preceding siblings ...)
  2025-11-18  8:22 ` [RFC PATCH 6/7] exfat: introduce exfat_count_contig_clusters Chi Zhiling
@ 2025-11-18  8:22 ` Chi Zhiling
  2025-11-28  2:48   ` Sungjong Seo
  2025-11-21  1:17 ` [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters Namjae Jeon
  7 siblings, 1 reply; 16+ messages in thread
From: Chi Zhiling @ 2025-11-18  8:22 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Sungjong Seo, Yuezhang Mo, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

mpage uses the get_block of the file system to obtain the mapping of a
file or allocate blocks for writes. Currently exfat only supports
obtaining one cluster in each get_block call.

Since exfat_count_contig_clusters can obtain multiple consecutive clusters,
it can be used to improve exfat_get_block when page size is larger than
cluster size.

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

diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
index f9501c3a3666..256ba2af34eb 100644
--- a/fs/exfat/inode.c
+++ b/fs/exfat/inode.c
@@ -264,13 +264,14 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
 static int exfat_get_block(struct inode *inode, sector_t iblock,
 		struct buffer_head *bh_result, int create)
 {
+	struct exfat_chain chain;
 	struct exfat_inode_info *ei = EXFAT_I(inode);
 	struct super_block *sb = inode->i_sb;
 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
 	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
 	int err = 0;
 	unsigned long mapped_blocks = 0;
-	unsigned int cluster, sec_offset;
+	unsigned int cluster, sec_offset, count;
 	sector_t last_block;
 	sector_t phys = 0;
 	sector_t valid_blks;
@@ -301,6 +302,17 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
 
 	phys = exfat_cluster_to_sector(sbi, cluster) + sec_offset;
 	mapped_blocks = sbi->sect_per_clus - sec_offset;
+
+	if (max_blocks > mapped_blocks && !create) {
+		chain.dir = cluster;
+		chain.size = (max_blocks >> sbi->sect_per_clus_bits) + 1;
+		chain.flags = ei->flags;
+
+		err = exfat_count_contig_clusters(sb, &chain, &count);
+		if (err)
+			return err;
+		max_blocks = (count << sbi->sect_per_clus_bits) - sec_offset;
+	}
 	max_blocks = min(mapped_blocks, max_blocks);
 
 	map_bh(bh_result, sb, phys);
-- 
2.43.0


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

* Re: [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters
  2025-11-18  8:22 [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
                   ` (6 preceding siblings ...)
  2025-11-18  8:22 ` [RFC PATCH 7/7] exfat: get mutil-clusters in exfat_get_block Chi Zhiling
@ 2025-11-21  1:17 ` Namjae Jeon
  2025-11-21  5:51   ` Chi Zhiling
  7 siblings, 1 reply; 16+ messages in thread
From: Namjae Jeon @ 2025-11-21  1:17 UTC (permalink / raw)
  To: Chi Zhiling
  Cc: linux-fsdevel, linux-kernel, Alexander Viro, Christian Brauner,
	Jan Kara, Matthew Wilcox, Sungjong Seo, Yuezhang Mo, Chi Zhiling

On Tue, Nov 18, 2025 at 5:26 PM Chi Zhiling <chizhiling@163.com> wrote:
>
> From: Chi Zhiling <chizhiling@kylinos.cn>
Hi Chi,
>
> The purpose of this patchset is to prepare for adapting exfat to iomap
> in the future. Currently, the main issue preventing exfat from supporting
> iomap is its inability to fetch multiple contiguous clusters.
Do you have a plan to work iomap support for exfat ?
>
> However, this patchset does not directly modify exfat_map_cluster and
> exfat_get_cluster to support multi-clusters. Instead, after obtaining
> the first cluster, it uses exfat_count_contig_clusters to retrieve the
> subsequent contiguous clusters.
>
> This approach is the one with the fewest changes among all the solutions
> I have attempted, making the modifications easier to review.
>
> This patchset includes two main changes: one reduces the number of sb_bread
> calls when accessing adjacent clusters to save time, and the other enables
> fetching multiple contiguous entries in exfat_get_blocks.
Are there any performance improvement measurements when applying this patch-set?

Thanks.
>
> Chi Zhiling (7):
>   exfat: add cache option for __exfat_ent_get
>   exfat: support reuse buffer head for exfat_ent_get
>   exfat: reuse cache to improve exfat_get_cluster
>   exfat: improve exfat_count_num_clusters
>   exfat: improve exfat_find_last_cluster
>   exfat: introduce exfat_count_contig_clusters
>   exfat: get mutil-clusters in exfat_get_block
>
>  fs/exfat/cache.c    | 11 ++++--
>  fs/exfat/exfat_fs.h |  6 ++-
>  fs/exfat/fatent.c   | 90 ++++++++++++++++++++++++++++++++++++---------
>  fs/exfat/inode.c    | 14 ++++++-
>  4 files changed, 97 insertions(+), 24 deletions(-)
>
> --
> 2.43.0
>

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

* Re: [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters
  2025-11-21  1:17 ` [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters Namjae Jeon
@ 2025-11-21  5:51   ` Chi Zhiling
  0 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-11-21  5:51 UTC (permalink / raw)
  To: Namjae Jeon
  Cc: linux-fsdevel, linux-kernel, Alexander Viro, Christian Brauner,
	Jan Kara, Matthew Wilcox, Sungjong Seo, Yuezhang Mo, Chi Zhiling

On 11/21/25 09:17, Namjae Jeon wrote:
> On Tue, Nov 18, 2025 at 5:26 PM Chi Zhiling <chizhiling@163.com> wrote:
>>
>> From: Chi Zhiling <chizhiling@kylinos.cn>
> Hi Chi,
>>
>> The purpose of this patchset is to prepare for adapting exfat to iomap
>> in the future. Currently, the main issue preventing exfat from supporting
>> iomap is its inability to fetch multiple contiguous clusters.
> Do you have a plan to work iomap support for exfat ?

Hi, Namjae


Firstly, I'm sorry that there are some errors in this patch. Due to my 
carelessness, the current patch did not work as expected. The parts that 
need to be modified are as follows:

diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
index 256ba2af34eb..e52af92b1732 100644
--- a/fs/exfat/inode.c
+++ b/fs/exfat/inode.c
@@ -311,7 +311,7 @@ static int exfat_get_block(struct inode *inode, 
sector_t iblock,
                 err = exfat_count_contig_clusters(sb, &chain, &count);
                 if (err)
                         return err;
-               max_blocks = (count << sbi->sect_per_clus_bits) - 
sec_offset;
+               mapped_blocks = (count << sbi->sect_per_clus_bits) - 
sec_offset;
         }
         max_blocks = min(mapped_blocks, max_blocks);


Back to the question, I do have plan to support iomap for exfat, but I'm 
still testing how much benefit switching to iomap will bring :)

>>
>> However, this patchset does not directly modify exfat_map_cluster and
>> exfat_get_cluster to support multi-clusters. Instead, after obtaining
>> the first cluster, it uses exfat_count_contig_clusters to retrieve the
>> subsequent contiguous clusters.
>>
>> This approach is the one with the fewest changes among all the solutions
>> I have attempted, making the modifications easier to review.
>>
>> This patchset includes two main changes: one reduces the number of sb_bread
>> calls when accessing adjacent clusters to save time, and the other enables
>> fetching multiple contiguous entries in exfat_get_blocks.
> Are there any performance improvement measurements when applying this patch-set?

I don't have very detailed performance data yet,

With the fix above, I did a simple read test with big file (30G) on my 
pc (cluster = 512), no significantly improvement in IO read speed. but 
the time proportion of exfat_get_block has decreased.

NO_FAT_CHAIN file:
IO speed:                           2.9G/s -> 3.0G/s
proportion of exfat_get_block       26.7% -> 0.2%

FAT_CHAIN file:
IO speed:                           416M/s -> 444M/s
proportion of exfat_get_block       58% -> 27%

Thanks,

>>
>> Chi Zhiling (7):
>>    exfat: add cache option for __exfat_ent_get
>>    exfat: support reuse buffer head for exfat_ent_get
>>    exfat: reuse cache to improve exfat_get_cluster
>>    exfat: improve exfat_count_num_clusters
>>    exfat: improve exfat_find_last_cluster
>>    exfat: introduce exfat_count_contig_clusters
>>    exfat: get mutil-clusters in exfat_get_block
>>
>>   fs/exfat/cache.c    | 11 ++++--
>>   fs/exfat/exfat_fs.h |  6 ++-
>>   fs/exfat/fatent.c   | 90 ++++++++++++++++++++++++++++++++++++---------
>>   fs/exfat/inode.c    | 14 ++++++-
>>   4 files changed, 97 insertions(+), 24 deletions(-)
>>
>> --
>> 2.43.0
>>


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

* Re: [RFC PATCH 7/7] exfat: get mutil-clusters in exfat_get_block
  2025-11-18  8:22 ` [RFC PATCH 7/7] exfat: get mutil-clusters in exfat_get_block Chi Zhiling
@ 2025-11-28  2:48   ` Sungjong Seo
  2025-11-28  6:18     ` Chi Zhiling
  0 siblings, 1 reply; 16+ messages in thread
From: Sungjong Seo @ 2025-11-28  2:48 UTC (permalink / raw)
  To: Chi Zhiling, linux-fsdevel, linux-kernel
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Yuezhang Mo, Chi Zhiling, Sungjong Seo


Hi, Chi,
On 25. 11. 18. 17:22, Chi Zhiling wrote:
> From: Chi Zhiling <chizhiling@kylinos.cn>
> 
> mpage uses the get_block of the file system to obtain the mapping of a
> file or allocate blocks for writes. Currently exfat only supports
> obtaining one cluster in each get_block call.
> 
> Since exfat_count_contig_clusters can obtain multiple consecutive clusters,
> it can be used to improve exfat_get_block when page size is larger than
> cluster size.

I think reusing buffer_head is a good approach!
However, for obtaining multiple clusters, it would be better to handle
them in exfat_map_cluster.

> 
> Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
> ---
>  fs/exfat/inode.c | 14 +++++++++++++-
>  1 file changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
> index f9501c3a3666..256ba2af34eb 100644
> --- a/fs/exfat/inode.c
> +++ b/fs/exfat/inode.c
> @@ -264,13 +264,14 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
>  static int exfat_get_block(struct inode *inode, sector_t iblock,
>  		struct buffer_head *bh_result, int create)
>  {
> +	struct exfat_chain chain;
>  	struct exfat_inode_info *ei = EXFAT_I(inode);
>  	struct super_block *sb = inode->i_sb;
>  	struct exfat_sb_info *sbi = EXFAT_SB(sb);
>  	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
>  	int err = 0;
>  	unsigned long mapped_blocks = 0;
> -	unsigned int cluster, sec_offset;
> +	unsigned int cluster, sec_offset, count;
>  	sector_t last_block;
>  	sector_t phys = 0;
>  	sector_t valid_blks;
> @@ -301,6 +302,17 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
>  
>  	phys = exfat_cluster_to_sector(sbi, cluster) + sec_offset;
>  	mapped_blocks = sbi->sect_per_clus - sec_offset;
> +
> +	if (max_blocks > mapped_blocks && !create) {
> +		chain.dir = cluster;
> +		chain.size = (max_blocks >> sbi->sect_per_clus_bits) + 1;

There seems to be an issue where the code sets chain.size to be one greater than the actual cluster count.

For example, assuming a 16KiB page, 512B sector, and 4KiB cluster,
for a 16KiB file, chain.size becomes 5 instead of 4.
Is this the intended behavior?

> +		chain.flags = ei->flags;
> +
> +		err = exfat_count_contig_clusters(sb, &chain, &count);
> +		if (err)
> +			return err;
> +		max_blocks = (count << sbi->sect_per_clus_bits) - sec_offset;

You already said mapped_blocks is correct.

> +	}
>  	max_blocks = min(mapped_blocks, max_blocks);
>  
>  	map_bh(bh_result, sb, phys);


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

* Re: [RFC PATCH 7/7] exfat: get mutil-clusters in exfat_get_block
  2025-11-28  2:48   ` Sungjong Seo
@ 2025-11-28  6:18     ` Chi Zhiling
  2025-12-04 12:18       ` Sungjong Seo
  0 siblings, 1 reply; 16+ messages in thread
From: Chi Zhiling @ 2025-11-28  6:18 UTC (permalink / raw)
  To: Sungjong Seo, linux-fsdevel, linux-kernel
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Yuezhang Mo, Chi Zhiling

On 11/28/25 10:48, Sungjong Seo wrote:
> 
> Hi, Chi,
> On 25. 11. 18. 17:22, Chi Zhiling wrote:
>> From: Chi Zhiling <chizhiling@kylinos.cn>
>>
>> mpage uses the get_block of the file system to obtain the mapping of a
>> file or allocate blocks for writes. Currently exfat only supports
>> obtaining one cluster in each get_block call.
>>
>> Since exfat_count_contig_clusters can obtain multiple consecutive clusters,
>> it can be used to improve exfat_get_block when page size is larger than
>> cluster size.
> 
> I think reusing buffer_head is a good approach!
> However, for obtaining multiple clusters, it would be better to handle
> them in exfat_map_cluster.

Hi, Sungjong

I agree.

My original plan was to support multiple clusters for exfat_map_cluster 
and exfat_get_cluster. since the changes required were quite extensive, 
I put that plan on hold. This would likely involve refactoring 
exfat_map_clusterand introducing iterators to reduce the number of 
parameters it needs

I will take some time to consider the signature of the new 
exfat_map_clusters. Do you have any thoughts about this?

> 
>>
>> Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
>> ---
>>   fs/exfat/inode.c | 14 +++++++++++++-
>>   1 file changed, 13 insertions(+), 1 deletion(-)
>>
>> diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
>> index f9501c3a3666..256ba2af34eb 100644
>> --- a/fs/exfat/inode.c
>> +++ b/fs/exfat/inode.c
>> @@ -264,13 +264,14 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
>>   static int exfat_get_block(struct inode *inode, sector_t iblock,
>>   		struct buffer_head *bh_result, int create)
>>   {
>> +	struct exfat_chain chain;
>>   	struct exfat_inode_info *ei = EXFAT_I(inode);
>>   	struct super_block *sb = inode->i_sb;
>>   	struct exfat_sb_info *sbi = EXFAT_SB(sb);
>>   	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
>>   	int err = 0;
>>   	unsigned long mapped_blocks = 0;
>> -	unsigned int cluster, sec_offset;
>> +	unsigned int cluster, sec_offset, count;
>>   	sector_t last_block;
>>   	sector_t phys = 0;
>>   	sector_t valid_blks;
>> @@ -301,6 +302,17 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
>>   
>>   	phys = exfat_cluster_to_sector(sbi, cluster) + sec_offset;
>>   	mapped_blocks = sbi->sect_per_clus - sec_offset;
>> +
>> +	if (max_blocks > mapped_blocks && !create) {
>> +		chain.dir = cluster;
>> +		chain.size = (max_blocks >> sbi->sect_per_clus_bits) + 1;
> 
> There seems to be an issue where the code sets chain.size to be one greater than the actual cluster count.
> 
> For example, assuming a 16KiB page, 512B sector, and 4KiB cluster,
> for a 16KiB file, chain.size becomes 5 instead of 4.
> Is this the intended behavior?

This is not the expected behavior. It's a serious bug. Thank you very 
much for pointing this out.

> 
>> +		chain.flags = ei->flags;
>> +
>> +		err = exfat_count_contig_clusters(sb, &chain, &count);
>> +		if (err)
>> +			return err;
>> +		max_blocks = (count << sbi->sect_per_clus_bits) - sec_offset;
> 
> You already said mapped_blocks is correct.
> 
>> +	}
>>   	max_blocks = min(mapped_blocks, max_blocks);
>>   
>>   	map_bh(bh_result, sb, phys);


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

* Re: [RFC PATCH 6/7] exfat: introduce exfat_count_contig_clusters
  2025-11-18  8:22 ` [RFC PATCH 6/7] exfat: introduce exfat_count_contig_clusters Chi Zhiling
@ 2025-11-28 11:09   ` Yuezhang.Mo
  2025-11-29  1:56     ` Chi Zhiling
  0 siblings, 1 reply; 16+ messages in thread
From: Yuezhang.Mo @ 2025-11-28 11:09 UTC (permalink / raw)
  To: Chi Zhiling, linux-fsdevel@vger.kernel.org,
	linux-kernel@vger.kernel.org
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Sungjong Seo, Chi Zhiling

> From: Chi Zhiling <chizhiling@kylinos.cn>
> 
> This patch introduces exfat_count_contig_clusters to obtain batch entries,
> which is an infrastructure used to support iomap.
> 
> Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
> ---
>  fs/exfat/exfat_fs.h |  2 ++
>  fs/exfat/fatent.c   | 33 +++++++++++++++++++++++++++++++++
>  2 files changed, 35 insertions(+)
> 
> diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
> index d52893276e9a..421dd7c61cca 100644
> --- a/fs/exfat/exfat_fs.h
> +++ b/fs/exfat/exfat_fs.h
> @@ -449,6 +449,8 @@ int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain,
>                 unsigned int *ret_clu);
>  int exfat_count_num_clusters(struct super_block *sb,
>                 struct exfat_chain *p_chain, unsigned int *ret_count);
> +int exfat_count_contig_clusters(struct super_block *sb,
> +               struct exfat_chain *p_chain, unsigned int *ret_count);
> 
>  /* balloc.c */
>  int exfat_load_bitmap(struct super_block *sb);
> diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c
> index d980d17176c2..9dcee9524155 100644
> --- a/fs/exfat/fatent.c
> +++ b/fs/exfat/fatent.c
> @@ -524,3 +524,36 @@ int exfat_count_num_clusters(struct super_block *sb,
> 
>         return 0;
>  }
> +
> +int exfat_count_contig_clusters(struct super_block *sb,
> +               struct exfat_chain *p_chain, unsigned int *ret_count)
> +{
> +       struct buffer_head *bh = NULL;
> +       unsigned int clu, next_clu;
> +       unsigned int count;
> +
> +       if (!p_chain->dir || p_chain->dir == EXFAT_EOF_CLUSTER) {
> +               *ret_count = 0;
> +               return 0;
> +       }
> +
> +       if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
> +               *ret_count = p_chain->size;
> +               return 0;
> +       }
> +
> +       clu = p_chain->dir;
> +       for (count = 1; count < p_chain->size; count++) {
> +               if (exfat_ent_get(sb, clu, &next_clu, &bh))
> +                       return -EIO;
> +               if (++clu != next_clu)
> +                       break;
> +       }
> +
> +       /* TODO: Update p_claim to help caller read ahead the next block */
> +
> +       brelse(bh);
> +       *ret_count = count;
> +
> +       return 0;
> +}

Hi Chi,

The clusters traversed in exfat_get_cluster() are cached to
->cache_lru, but the clusters traversed in this function are
not.

I think we can implement this functionality in exfat_get_cluster()
and cache the clusters.

> --
> 2.43.0

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

* Re: [RFC PATCH 6/7] exfat: introduce exfat_count_contig_clusters
  2025-11-28 11:09   ` Yuezhang.Mo
@ 2025-11-29  1:56     ` Chi Zhiling
  0 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-11-29  1:56 UTC (permalink / raw)
  To: Yuezhang.Mo@sony.com, linux-fsdevel@vger.kernel.org,
	linux-kernel@vger.kernel.org
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Sungjong Seo, Chi Zhiling

On 11/28/25 19:09, Yuezhang.Mo@sony.com wrote:
>> From: Chi Zhiling <chizhiling@kylinos.cn>
>>
>> This patch introduces exfat_count_contig_clusters to obtain batch entries,
>> which is an infrastructure used to support iomap.
>>
>> Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
>> ---
>>   fs/exfat/exfat_fs.h |  2 ++
>>   fs/exfat/fatent.c   | 33 +++++++++++++++++++++++++++++++++
>>   2 files changed, 35 insertions(+)
>>
>> diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
>> index d52893276e9a..421dd7c61cca 100644
>> --- a/fs/exfat/exfat_fs.h
>> +++ b/fs/exfat/exfat_fs.h
>> @@ -449,6 +449,8 @@ int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain,
>>                  unsigned int *ret_clu);
>>   int exfat_count_num_clusters(struct super_block *sb,
>>                  struct exfat_chain *p_chain, unsigned int *ret_count);
>> +int exfat_count_contig_clusters(struct super_block *sb,
>> +               struct exfat_chain *p_chain, unsigned int *ret_count);
>>
>>   /* balloc.c */
>>   int exfat_load_bitmap(struct super_block *sb);
>> diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c
>> index d980d17176c2..9dcee9524155 100644
>> --- a/fs/exfat/fatent.c
>> +++ b/fs/exfat/fatent.c
>> @@ -524,3 +524,36 @@ int exfat_count_num_clusters(struct super_block *sb,
>>
>>          return 0;
>>   }
>> +
>> +int exfat_count_contig_clusters(struct super_block *sb,
>> +               struct exfat_chain *p_chain, unsigned int *ret_count)
>> +{
>> +       struct buffer_head *bh = NULL;
>> +       unsigned int clu, next_clu;
>> +       unsigned int count;
>> +
>> +       if (!p_chain->dir || p_chain->dir == EXFAT_EOF_CLUSTER) {
>> +               *ret_count = 0;
>> +               return 0;
>> +       }
>> +
>> +       if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
>> +               *ret_count = p_chain->size;
>> +               return 0;
>> +       }
>> +
>> +       clu = p_chain->dir;
>> +       for (count = 1; count < p_chain->size; count++) {
>> +               if (exfat_ent_get(sb, clu, &next_clu, &bh))
>> +                       return -EIO;
>> +               if (++clu != next_clu)
>> +                       break;
>> +       }
>> +
>> +       /* TODO: Update p_claim to help caller read ahead the next block */
>> +
>> +       brelse(bh);
>> +       *ret_count = count;
>> +
>> +       return 0;
>> +}
> 
> Hi Chi,
> 
> The clusters traversed in exfat_get_cluster() are cached to
> ->cache_lru, but the clusters traversed in this function are
> not.
> 
> I think we can implement this functionality in exfat_get_cluster()
> and cache the clusters.

Agreed, I will implement it in the next version.


Thanks,

> 
>> --
>> 2.43.0


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

* Re: [RFC PATCH 7/7] exfat: get mutil-clusters in exfat_get_block
  2025-11-28  6:18     ` Chi Zhiling
@ 2025-12-04 12:18       ` Sungjong Seo
  2025-12-05 11:36         ` Chi Zhiling
  0 siblings, 1 reply; 16+ messages in thread
From: Sungjong Seo @ 2025-12-04 12:18 UTC (permalink / raw)
  To: Chi Zhiling, linux-fsdevel, linux-kernel
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Yuezhang Mo, Chi Zhiling



On 25. 11. 28. 15:18, Chi Zhiling wrote:
> On 11/28/25 10:48, Sungjong Seo wrote:
>>
>> Hi, Chi,
>> On 25. 11. 18. 17:22, Chi Zhiling wrote:
>>> From: Chi Zhiling <chizhiling@kylinos.cn>
>>>
>>> mpage uses the get_block of the file system to obtain the mapping of a
>>> file or allocate blocks for writes. Currently exfat only supports
>>> obtaining one cluster in each get_block call.
>>>
>>> Since exfat_count_contig_clusters can obtain multiple consecutive clusters,
>>> it can be used to improve exfat_get_block when page size is larger than
>>> cluster size.
>>
>> I think reusing buffer_head is a good approach!
>> However, for obtaining multiple clusters, it would be better to handle
>> them in exfat_map_cluster.
> 
> Hi, Sungjong
> 
> I agree.
> 
> My original plan was to support multiple clusters for exfat_map_cluster and exfat_get_cluster. since the changes required were quite extensive, I put that plan on hold. This would likely involve refactoring exfat_map_clusterand introducing iterators to reduce the number of parameters it needs
> 
> I will take some time to consider the signature of the new exfat_map_clusters. Do you have any thoughts about this?
Apologies, I missed your email.
IMO, we don't need to rush, so I think expanding exfat_map_cluster(s) would be better.

Thanks.
> 
>>
>>>
>>> Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
>>> ---
>>>   fs/exfat/inode.c | 14 +++++++++++++-
>>>   1 file changed, 13 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
>>> index f9501c3a3666..256ba2af34eb 100644
>>> --- a/fs/exfat/inode.c
>>> +++ b/fs/exfat/inode.c
>>> @@ -264,13 +264,14 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
>>>   static int exfat_get_block(struct inode *inode, sector_t iblock,
>>>           struct buffer_head *bh_result, int create)
>>>   {
>>> +    struct exfat_chain chain;
>>>       struct exfat_inode_info *ei = EXFAT_I(inode);
>>>       struct super_block *sb = inode->i_sb;
>>>       struct exfat_sb_info *sbi = EXFAT_SB(sb);
>>>       unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
>>>       int err = 0;
>>>       unsigned long mapped_blocks = 0;
>>> -    unsigned int cluster, sec_offset;
>>> +    unsigned int cluster, sec_offset, count;
>>>       sector_t last_block;
>>>       sector_t phys = 0;
>>>       sector_t valid_blks;
>>> @@ -301,6 +302,17 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
>>>         phys = exfat_cluster_to_sector(sbi, cluster) + sec_offset;
>>>       mapped_blocks = sbi->sect_per_clus - sec_offset;
>>> +
>>> +    if (max_blocks > mapped_blocks && !create) {
>>> +        chain.dir = cluster;
>>> +        chain.size = (max_blocks >> sbi->sect_per_clus_bits) + 1;
>>
>> There seems to be an issue where the code sets chain.size to be one greater than the actual cluster count.
>>
>> For example, assuming a 16KiB page, 512B sector, and 4KiB cluster,
>> for a 16KiB file, chain.size becomes 5 instead of 4.
>> Is this the intended behavior?
> 
> This is not the expected behavior. It's a serious bug. Thank you very much for pointing this out.
> 
>>
>>> +        chain.flags = ei->flags;
>>> +
>>> +        err = exfat_count_contig_clusters(sb, &chain, &count);
>>> +        if (err)
>>> +            return err;
>>> +        max_blocks = (count << sbi->sect_per_clus_bits) - sec_offset;
>>
>> You already said mapped_blocks is correct.
>>
>>> +    }
>>>       max_blocks = min(mapped_blocks, max_blocks);
>>>         map_bh(bh_result, sb, phys);
> 
> 


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

* Re: [RFC PATCH 7/7] exfat: get mutil-clusters in exfat_get_block
  2025-12-04 12:18       ` Sungjong Seo
@ 2025-12-05 11:36         ` Chi Zhiling
  0 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-12-05 11:36 UTC (permalink / raw)
  To: Sungjong Seo, linux-fsdevel, linux-kernel
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Wilcox,
	Namjae Jeon, Yuezhang Mo, Chi Zhiling

On 12/4/25 20:18, Sungjong Seo wrote:
> 
> 
> On 25. 11. 28. 15:18, Chi Zhiling wrote:
>> On 11/28/25 10:48, Sungjong Seo wrote:
>>>
>>> Hi, Chi,
>>> On 25. 11. 18. 17:22, Chi Zhiling wrote:
>>>> From: Chi Zhiling <chizhiling@kylinos.cn>
>>>>
>>>> mpage uses the get_block of the file system to obtain the mapping of a
>>>> file or allocate blocks for writes. Currently exfat only supports
>>>> obtaining one cluster in each get_block call.
>>>>
>>>> Since exfat_count_contig_clusters can obtain multiple consecutive clusters,
>>>> it can be used to improve exfat_get_block when page size is larger than
>>>> cluster size.
>>>
>>> I think reusing buffer_head is a good approach!
>>> However, for obtaining multiple clusters, it would be better to handle
>>> them in exfat_map_cluster.
>>
>> Hi, Sungjong
>>
>> I agree.
>>
>> My original plan was to support multiple clusters for exfat_map_cluster and exfat_get_cluster. since the changes required were quite extensive, I put that plan on hold. This would likely involve refactoring exfat_map_clusterand introducing iterators to reduce the number of parameters it needs
>>
>> I will take some time to consider the signature of the new exfat_map_clusters. Do you have any thoughts about this?
> Apologies, I missed your email.
> IMO, we don't need to rush, so I think expanding exfat_map_cluster(s) would be better.

Okay.

> 
> Thanks.
>>
>>>
>>>>
>>>> Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
>>>> ---
>>>>    fs/exfat/inode.c | 14 +++++++++++++-
>>>>    1 file changed, 13 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
>>>> index f9501c3a3666..256ba2af34eb 100644
>>>> --- a/fs/exfat/inode.c
>>>> +++ b/fs/exfat/inode.c
>>>> @@ -264,13 +264,14 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
>>>>    static int exfat_get_block(struct inode *inode, sector_t iblock,
>>>>            struct buffer_head *bh_result, int create)
>>>>    {
>>>> +    struct exfat_chain chain;
>>>>        struct exfat_inode_info *ei = EXFAT_I(inode);
>>>>        struct super_block *sb = inode->i_sb;
>>>>        struct exfat_sb_info *sbi = EXFAT_SB(sb);
>>>>        unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
>>>>        int err = 0;
>>>>        unsigned long mapped_blocks = 0;
>>>> -    unsigned int cluster, sec_offset;
>>>> +    unsigned int cluster, sec_offset, count;
>>>>        sector_t last_block;
>>>>        sector_t phys = 0;
>>>>        sector_t valid_blks;
>>>> @@ -301,6 +302,17 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
>>>>          phys = exfat_cluster_to_sector(sbi, cluster) + sec_offset;
>>>>        mapped_blocks = sbi->sect_per_clus - sec_offset;
>>>> +
>>>> +    if (max_blocks > mapped_blocks && !create) {
>>>> +        chain.dir = cluster;
>>>> +        chain.size = (max_blocks >> sbi->sect_per_clus_bits) + 1;
>>>
>>> There seems to be an issue where the code sets chain.size to be one greater than the actual cluster count.
>>>
>>> For example, assuming a 16KiB page, 512B sector, and 4KiB cluster,
>>> for a 16KiB file, chain.size becomes 5 instead of 4.
>>> Is this the intended behavior?
>>
>> This is not the expected behavior. It's a serious bug. Thank you very much for pointing this out.
>>
>>>
>>>> +        chain.flags = ei->flags;
>>>> +
>>>> +        err = exfat_count_contig_clusters(sb, &chain, &count);
>>>> +        if (err)
>>>> +            return err;
>>>> +        max_blocks = (count << sbi->sect_per_clus_bits) - sec_offset;
>>>
>>> You already said mapped_blocks is correct.
>>>
>>>> +    }
>>>>        max_blocks = min(mapped_blocks, max_blocks);
>>>>          map_bh(bh_result, sb, phys);
>>
>>


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

end of thread, other threads:[~2025-12-05 11:37 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-18  8:22 [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
2025-11-18  8:22 ` [RFC PATCH 1/7] exfat: add cache option for __exfat_ent_get Chi Zhiling
2025-11-18  8:22 ` [RFC PATCH 2/7] exfat: support reuse buffer head for exfat_ent_get Chi Zhiling
2025-11-18  8:22 ` [RFC PATCH 3/7] exfat: reuse cache to improve exfat_get_cluster Chi Zhiling
2025-11-18  8:22 ` [RFC PATCH 4/7] exfat: improve exfat_count_num_clusters Chi Zhiling
2025-11-18  8:22 ` [RFC PATCH 5/7] exfat: improve exfat_find_last_cluster Chi Zhiling
2025-11-18  8:22 ` [RFC PATCH 6/7] exfat: introduce exfat_count_contig_clusters Chi Zhiling
2025-11-28 11:09   ` Yuezhang.Mo
2025-11-29  1:56     ` Chi Zhiling
2025-11-18  8:22 ` [RFC PATCH 7/7] exfat: get mutil-clusters in exfat_get_block Chi Zhiling
2025-11-28  2:48   ` Sungjong Seo
2025-11-28  6:18     ` Chi Zhiling
2025-12-04 12:18       ` Sungjong Seo
2025-12-05 11:36         ` Chi Zhiling
2025-11-21  1:17 ` [RFC PATCH 0/7] Enable exfat_get_block to support obtaining multiple clusters Namjae Jeon
2025-11-21  5:51   ` Chi Zhiling

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).