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

From: Chi Zhiling <chizhiling@kylinos.cn>

This patch series significantly improves exFAT read performance
by adding multi-cluster mapping support.
The changes reduce get_block calls during sequential reads,
particularly benefiting small cluster sizes.

- Extends exfat_get_cluster() and exfat_map_cluster() to handle multiple contiguous clusters
- Adds buffer head caching for FAT table reads

Performance results show ~10% improvement for 512-byte clusters (454->511 MB/s)
and reduced get_block overhead from 10.8% to 0.02% for NO_FAT_CHAIN files.

All criticism and suggestions are welcome :)

Chi Zhiling (9):
  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: remove unused parameters from exfat_get_cluster
  exfat: tweak exfat_cache_lookup to support zero offset cluster
  exfat: support multi-cluster for exfat_map_cluster
  exfat: support multi-cluster for exfat_get_cluster

 fs/exfat/cache.c    | 108 ++++++++++++++++++++++++++++----------------
 fs/exfat/exfat_fs.h |   7 ++-
 fs/exfat/fatent.c   |  61 ++++++++++++++++---------
 fs/exfat/inode.c    |  46 +++++++++++--------
 4 files changed, 137 insertions(+), 85 deletions(-)

-- 
2.43.0


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

* [PATCH v1 1/9] exfat: add cache option for __exfat_ent_get
  2025-12-26  9:44 [PATCH v1 0/9] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
@ 2025-12-26  9:44 ` Chi Zhiling
  2025-12-26  9:44 ` [PATCH v1 2/9] exfat: support reuse buffer head for exfat_ent_get Chi Zhiling
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-12-26  9:44 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Namjae Jeon, Sungjong Seo, Yuezhang Mo, Alexander Viro,
	Christian Brauner, Jan Kara, Matthew Wilcox, 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 c9c5f2e3a05e..0cfbc0b435bd 100644
--- a/fs/exfat/fatent.c
+++ b/fs/exfat/fatent.c
@@ -36,18 +36,23 @@ 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 (last)
+			*last = bh;
+		if (unlikely(!bh))
+			return -EIO;
+	}
 
 	*content = le32_to_cpu(*(__le32 *)(&bh->b_data[off]));
 
@@ -55,7 +60,8 @@ 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)
+		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	[flat|nested] 16+ messages in thread

* [PATCH v1 2/9] exfat: support reuse buffer head for exfat_ent_get
  2025-12-26  9:44 [PATCH v1 0/9] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
  2025-12-26  9:44 ` [PATCH v1 1/9] exfat: add cache option for __exfat_ent_get Chi Zhiling
@ 2025-12-26  9:44 ` Chi Zhiling
  2025-12-26  9:44 ` [PATCH v1 3/9] exfat: reuse cache to improve exfat_get_cluster Chi Zhiling
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-12-26  9:44 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Namjae Jeon, Sungjong Seo, Yuezhang Mo, Alexander Viro,
	Christian Brauner, Jan Kara, Matthew Wilcox, 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   | 39 ++++++++++++++++++++++++---------------
 3 files changed, 27 insertions(+), 18 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 176fef62574c..f7f25e0600c7 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -432,13 +432,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 0cfbc0b435bd..679688cfea01 100644
--- a/fs/exfat/fatent.c
+++ b/fs/exfat/fatent.c
@@ -88,49 +88,58 @@ 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;
 
 	if (!is_valid_cluster(sbi, 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) {
+	if (unlikely(__exfat_ent_get(sb, loc, content, last))) {
 		exfat_fs_error_ratelimit(sb,
-			"failed to access to FAT (entry 0x%08x, err:%d)",
-			loc, err);
-		return err;
+			"failed to access to FAT (entry 0x%08x)",
+			loc);
+		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 -EIO;
 }
 
 int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain,
@@ -299,7 +308,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 +499,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	[flat|nested] 16+ messages in thread

* [PATCH v1 3/9] exfat: reuse cache to improve exfat_get_cluster
  2025-12-26  9:44 [PATCH v1 0/9] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
  2025-12-26  9:44 ` [PATCH v1 1/9] exfat: add cache option for __exfat_ent_get Chi Zhiling
  2025-12-26  9:44 ` [PATCH v1 2/9] exfat: support reuse buffer head for exfat_ent_get Chi Zhiling
@ 2025-12-26  9:44 ` Chi Zhiling
  2025-12-26  9:44 ` [PATCH v1 4/9] exfat: improve exfat_count_num_clusters Chi Zhiling
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-12-26  9:44 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Namjae Jeon, Sungjong Seo, Yuezhang Mo, Alexander Viro,
	Christian Brauner, Jan Kara, Matthew Wilcox, 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 | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c
index 61af3fa05ab7..4161b983b6af 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,11 +285,11 @@ 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))
-			return -EIO;
+		if (exfat_ent_get(sb, *dclus, &content, &bh))
+			goto err;
 
 		*last_dclus = *dclus;
 		*dclus = content;
@@ -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	[flat|nested] 16+ messages in thread

* [PATCH v1 4/9] exfat: improve exfat_count_num_clusters
  2025-12-26  9:44 [PATCH v1 0/9] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
                   ` (2 preceding siblings ...)
  2025-12-26  9:44 ` [PATCH v1 3/9] exfat: reuse cache to improve exfat_get_cluster Chi Zhiling
@ 2025-12-26  9:44 ` Chi Zhiling
  2025-12-26  9:44 ` [PATCH v1 5/9] exfat: improve exfat_find_last_cluster Chi Zhiling
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-12-26  9:44 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Namjae Jeon, Sungjong Seo, Yuezhang Mo, Alexander Viro,
	Christian Brauner, Jan Kara, Matthew Wilcox, 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 679688cfea01..f060eab2f2f2 100644
--- a/fs/exfat/fatent.c
+++ b/fs/exfat/fatent.c
@@ -484,6 +484,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;
@@ -499,12 +500,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	[flat|nested] 16+ messages in thread

* [PATCH v1 5/9] exfat: improve exfat_find_last_cluster
  2025-12-26  9:44 [PATCH v1 0/9] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
                   ` (3 preceding siblings ...)
  2025-12-26  9:44 ` [PATCH v1 4/9] exfat: improve exfat_count_num_clusters Chi Zhiling
@ 2025-12-26  9:44 ` Chi Zhiling
  2025-12-26  9:44 ` [PATCH v1 6/9] exfat: remove unused parameters from exfat_get_cluster Chi Zhiling
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-12-26  9:44 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Namjae Jeon, Sungjong Seo, Yuezhang Mo, Alexander Viro,
	Christian Brauner, Jan Kara, Matthew Wilcox, 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 f060eab2f2f2..71ee16479c43 100644
--- a/fs/exfat/fatent.c
+++ b/fs/exfat/fatent.c
@@ -296,6 +296,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;
 
@@ -308,10 +309,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	[flat|nested] 16+ messages in thread

* [PATCH v1 6/9] exfat: remove unused parameters from exfat_get_cluster
  2025-12-26  9:44 [PATCH v1 0/9] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
                   ` (4 preceding siblings ...)
  2025-12-26  9:44 ` [PATCH v1 5/9] exfat: improve exfat_find_last_cluster Chi Zhiling
@ 2025-12-26  9:44 ` Chi Zhiling
  2025-12-26  9:44 ` [PATCH v1 7/9] exfat: tweak exfat_cache_lookup to support zero offset cluster Chi Zhiling
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-12-26  9:44 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Namjae Jeon, Sungjong Seo, Yuezhang Mo, Alexander Viro,
	Christian Brauner, Jan Kara, Matthew Wilcox, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

Remove the unused fclus and allow_eof parameters from exfat_get_cluster.
The fclus parameter is changed to a local variable as it is not needed
to be returned. The allow_eof parameter was always 1, so remove it and
the associated error handling.

This simplifies the function and its callers, no logical changes.

Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
 fs/exfat/cache.c    | 31 +++++++++++--------------------
 fs/exfat/exfat_fs.h |  3 +--
 fs/exfat/inode.c    | 12 +++++-------
 3 files changed, 17 insertions(+), 29 deletions(-)

diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c
index 4161b983b6af..43a6aa87c55d 100644
--- a/fs/exfat/cache.c
+++ b/fs/exfat/cache.c
@@ -234,8 +234,7 @@ static inline void cache_init(struct exfat_cache_id *cid,
 }
 
 int exfat_get_cluster(struct inode *inode, unsigned int cluster,
-		unsigned int *fclus, unsigned int *dclus,
-		unsigned int *last_dclus, int allow_eof)
+		unsigned int *dclus, unsigned int *last_dclus)
 {
 	struct super_block *sb = inode->i_sb;
 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
@@ -243,7 +242,7 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 	struct exfat_inode_info *ei = EXFAT_I(inode);
 	struct buffer_head *bh = NULL;
 	struct exfat_cache_id cid;
-	unsigned int content;
+	unsigned int content, fclus;
 
 	if (ei->start_clu == EXFAT_FREE_CLUSTER) {
 		exfat_fs_error(sb,
@@ -252,7 +251,7 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 		return -EIO;
 	}
 
-	*fclus = 0;
+	fclus = 0;
 	*dclus = ei->start_clu;
 	*last_dclus = *dclus;
 
@@ -264,7 +263,7 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 
 	cache_init(&cid, EXFAT_EOF_CLUSTER, EXFAT_EOF_CLUSTER);
 
-	if (exfat_cache_lookup(inode, cluster, &cid, fclus, dclus) ==
+	if (exfat_cache_lookup(inode, cluster, &cid, &fclus, dclus) ==
 			EXFAT_EOF_CLUSTER) {
 		/*
 		 * dummy, always not contiguous
@@ -276,15 +275,15 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 			cid.nr_contig != 0);
 	}
 
-	if (*fclus == cluster)
+	if (fclus == cluster)
 		return 0;
 
-	while (*fclus < cluster) {
+	while (fclus < cluster) {
 		/* prevent the infinite loop of cluster chain */
-		if (*fclus > limit) {
+		if (fclus > limit) {
 			exfat_fs_error(sb,
 				"detected the cluster chain loop (i_pos %u)",
-				(*fclus));
+				fclus);
 			goto err;
 		}
 
@@ -293,21 +292,13 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 
 		*last_dclus = *dclus;
 		*dclus = content;
-		(*fclus)++;
-
-		if (content == EXFAT_EOF_CLUSTER) {
-			if (!allow_eof) {
-				exfat_fs_error(sb,
-				       "invalid cluster chain (i_pos %u, last_clus 0x%08x is EOF)",
-				       *fclus, (*last_dclus));
-				goto err;
-			}
+		fclus++;
 
+		if (content == EXFAT_EOF_CLUSTER)
 			break;
-		}
 
 		if (!cache_contiguous(&cid, *dclus))
-			cache_init(&cid, *fclus, *dclus);
+			cache_init(&cid, fclus, *dclus);
 	}
 
 	brelse(bh);
diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index f7f25e0600c7..e58d8eed5495 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -486,8 +486,7 @@ int exfat_cache_init(void);
 void exfat_cache_shutdown(void);
 void exfat_cache_inval_inode(struct inode *inode);
 int exfat_get_cluster(struct inode *inode, unsigned int cluster,
-		unsigned int *fclus, unsigned int *dclus,
-		unsigned int *last_dclus, int allow_eof);
+		unsigned int *dclus, unsigned int *last_dclus);
 
 /* dir.c */
 extern const struct inode_operations exfat_dir_inode_operations;
diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
index f9501c3a3666..1062ce470cb1 100644
--- a/fs/exfat/inode.c
+++ b/fs/exfat/inode.c
@@ -157,28 +157,26 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
 				*clu += clu_offset;
 		}
 	} else if (ei->type == TYPE_FILE) {
-		unsigned int fclus = 0;
 		int err = exfat_get_cluster(inode, clu_offset,
-				&fclus, clu, &last_clu, 1);
+				clu, &last_clu);
 		if (err)
 			return -EIO;
-
-		clu_offset -= fclus;
 	} else {
+		unsigned int fclus = 0;
 		/* 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;
 			/* hint_bmap.clu should be valid */
 			WARN_ON(ei->hint_bmap.clu < 2);
+			fclus = ei->hint_bmap.off;
 			*clu = ei->hint_bmap.clu;
 		}
 
-		while (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) {
+		while (fclus < clu_offset && *clu != EXFAT_EOF_CLUSTER) {
 			last_clu = *clu;
 			if (exfat_get_next_cluster(sb, clu))
 				return -EIO;
-			clu_offset--;
+			fclus++;
 		}
 	}
 
-- 
2.43.0


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

* [PATCH v1 7/9] exfat: tweak exfat_cache_lookup to support zero offset cluster
  2025-12-26  9:44 [PATCH v1 0/9] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
                   ` (5 preceding siblings ...)
  2025-12-26  9:44 ` [PATCH v1 6/9] exfat: remove unused parameters from exfat_get_cluster Chi Zhiling
@ 2025-12-26  9:44 ` Chi Zhiling
  2025-12-26  9:44 ` [PATCH v1 8/9] exfat: support multi-cluster for exfat_map_cluster Chi Zhiling
  2025-12-26  9:44 ` [PATCH v1 9/9] exfat: support multi-cluster for exfat_get_cluster Chi Zhiling
  8 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-12-26  9:44 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Namjae Jeon, Sungjong Seo, Yuezhang Mo, Alexander Viro,
	Christian Brauner, Jan Kara, Matthew Wilcox, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

The current cache mechanism does not support reading clusters from zero
file offset, so this patch modifies the exfat_cache_lookup function to
enable the cache to support multiple contiguous clusters which starting
from a zero offset, preparing for subsequent reads of contiguous clusters
from the zero offset.

Additionally, this patch removes unreachable WARN debugging code.

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

diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c
index 43a6aa87c55d..57a66c067394 100644
--- a/fs/exfat/cache.c
+++ b/fs/exfat/cache.c
@@ -80,19 +80,19 @@ static inline void exfat_cache_update_lru(struct inode *inode,
 		list_move(&cache->cache_list, &ei->cache_lru);
 }
 
-static unsigned int exfat_cache_lookup(struct inode *inode,
+static bool exfat_cache_lookup(struct inode *inode,
 		unsigned int fclus, struct exfat_cache_id *cid,
 		unsigned int *cached_fclus, unsigned int *cached_dclus)
 {
 	struct exfat_inode_info *ei = EXFAT_I(inode);
 	static struct exfat_cache nohit = { .fcluster = 0, };
 	struct exfat_cache *hit = &nohit, *p;
-	unsigned int offset = EXFAT_EOF_CLUSTER;
+	unsigned int offset;
 
 	spin_lock(&ei->cache_lru_lock);
 	list_for_each_entry(p, &ei->cache_lru, cache_list) {
 		/* Find the cache of "fclus" or nearest cache. */
-		if (p->fcluster <= fclus && hit->fcluster < p->fcluster) {
+		if (p->fcluster <= fclus && hit->fcluster <= p->fcluster) {
 			hit = p;
 			if (hit->fcluster + hit->nr_contig < fclus) {
 				offset = hit->nr_contig;
@@ -114,7 +114,7 @@ static unsigned int exfat_cache_lookup(struct inode *inode,
 	}
 	spin_unlock(&ei->cache_lru_lock);
 
-	return offset;
+	return hit != &nohit;
 }
 
 static struct exfat_cache *exfat_cache_merge(struct inode *inode,
@@ -261,19 +261,8 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 	if (cluster == 0 || *dclus == EXFAT_EOF_CLUSTER)
 		return 0;
 
-	cache_init(&cid, EXFAT_EOF_CLUSTER, EXFAT_EOF_CLUSTER);
-
-	if (exfat_cache_lookup(inode, cluster, &cid, &fclus, dclus) ==
-			EXFAT_EOF_CLUSTER) {
-		/*
-		 * dummy, always not contiguous
-		 * This is reinitialized by cache_init(), later.
-		 */
-		WARN_ON(cid.id != EXFAT_CACHE_VALID ||
-			cid.fcluster != EXFAT_EOF_CLUSTER ||
-			cid.dcluster != EXFAT_EOF_CLUSTER ||
-			cid.nr_contig != 0);
-	}
+	cache_init(&cid, fclus, *dclus);
+	exfat_cache_lookup(inode, cluster, &cid, &fclus, dclus);
 
 	if (fclus == cluster)
 		return 0;
-- 
2.43.0


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

* [PATCH v1 8/9] exfat: support multi-cluster for exfat_map_cluster
  2025-12-26  9:44 [PATCH v1 0/9] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
                   ` (6 preceding siblings ...)
  2025-12-26  9:44 ` [PATCH v1 7/9] exfat: tweak exfat_cache_lookup to support zero offset cluster Chi Zhiling
@ 2025-12-26  9:44 ` Chi Zhiling
  2025-12-26  9:44 ` [PATCH v1 9/9] exfat: support multi-cluster for exfat_get_cluster Chi Zhiling
  8 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-12-26  9:44 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Namjae Jeon, Sungjong Seo, Yuezhang Mo, Alexander Viro,
	Christian Brauner, Jan Kara, Matthew Wilcox, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

This patch introduces a parameter 'count' to support fetching multiple
clusters in exfat_map_cluster. The returned 'count' indicates the number
of consecutive clusters, or 0 when the input cluster offset is past EOF.

And the 'count' is also an input parameter for the caller to specify the
required number of clusters.

Only NO_FAT_CHAIN files enable multi-cluster fetching in this patch.

After this patch, the time proportion of exfat_get_block has decreased,
The performance data is as follows:

Cluster size: 512 bytes
Sequential read of a 30GB NO_FAT_CHAIN file:
2.4GB/s -> 2.5 GB/s
proportion of exfat_get_block:
10.8% -> 0.02%

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

diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
index 1062ce470cb1..8c49ab15eafe 100644
--- a/fs/exfat/inode.c
+++ b/fs/exfat/inode.c
@@ -124,7 +124,7 @@ void exfat_sync_inode(struct inode *inode)
  * *clu = (~0), if it's unable to allocate a new cluster
  */
 static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
-		unsigned int *clu, int create)
+		unsigned int *clu, unsigned int *count, int create)
 {
 	int ret;
 	unsigned int last_clu;
@@ -147,20 +147,23 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
 
 	*clu = last_clu = ei->start_clu;
 
-	if (ei->flags == ALLOC_NO_FAT_CHAIN) {
-		if (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) {
-			last_clu += clu_offset - 1;
-
-			if (clu_offset == num_clusters)
-				*clu = EXFAT_EOF_CLUSTER;
-			else
-				*clu += clu_offset;
+	if (*clu == EXFAT_EOF_CLUSTER) {
+		*count = 0;
+	} else if (ei->flags == ALLOC_NO_FAT_CHAIN) {
+		last_clu += num_clusters - 1;
+		if (clu_offset < num_clusters) {
+			*clu += clu_offset;
+			*count = num_clusters - clu_offset;
+		} else {
+			*clu = EXFAT_EOF_CLUSTER;
+			*count = 0;
 		}
 	} else if (ei->type == TYPE_FILE) {
 		int err = exfat_get_cluster(inode, clu_offset,
 				clu, &last_clu);
 		if (err)
 			return -EIO;
+		*count = (*clu == EXFAT_EOF_CLUSTER) ? 0 : 1;
 	} else {
 		unsigned int fclus = 0;
 		/* hint information */
@@ -178,6 +181,7 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
 				return -EIO;
 			fclus++;
 		}
+		*count = (*clu == EXFAT_EOF_CLUSTER) ? 0 : 1;
 	}
 
 	if (*clu == EXFAT_EOF_CLUSTER) {
@@ -249,7 +253,7 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
 				num_to_be_allocated--;
 			}
 		}
-
+		*count = 1;
 	}
 
 	/* hint information */
@@ -268,7 +272,7 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
 	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;
@@ -281,8 +285,9 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
 		goto done;
 
 	/* Is this block already allocated? */
+	count = EXFAT_B_TO_CLU_ROUND_UP(bh_result->b_size, sbi);
 	err = exfat_map_cluster(inode, iblock >> sbi->sect_per_clus_bits,
-			&cluster, create);
+			&cluster, &count, create);
 	if (err) {
 		if (err != -ENOSPC)
 			exfat_fs_error_ratelimit(sb,
@@ -293,12 +298,14 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
 
 	if (cluster == EXFAT_EOF_CLUSTER)
 		goto done;
+	if (WARN_ON_ONCE(!count))
+		count = 1;
 
 	/* sector offset in cluster */
 	sec_offset = iblock & (sbi->sect_per_clus - 1);
 
 	phys = exfat_cluster_to_sector(sbi, cluster) + sec_offset;
-	mapped_blocks = sbi->sect_per_clus - sec_offset;
+	mapped_blocks = count * sbi->sect_per_clus - sec_offset;
 	max_blocks = min(mapped_blocks, max_blocks);
 
 	map_bh(bh_result, sb, phys);
-- 
2.43.0


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

* [PATCH v1 9/9] exfat: support multi-cluster for exfat_get_cluster
  2025-12-26  9:44 [PATCH v1 0/9] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
                   ` (7 preceding siblings ...)
  2025-12-26  9:44 ` [PATCH v1 8/9] exfat: support multi-cluster for exfat_map_cluster Chi Zhiling
@ 2025-12-26  9:44 ` Chi Zhiling
  8 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2025-12-26  9:44 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel
  Cc: Namjae Jeon, Sungjong Seo, Yuezhang Mo, Alexander Viro,
	Christian Brauner, Jan Kara, Matthew Wilcox, Chi Zhiling

From: Chi Zhiling <chizhiling@kylinos.cn>

This patch introduces a count parameter to exfat_get_cluster, which
serves as an input parameter for the caller to specify the desired
number of clusters, and as an output parameter to store the length
of consecutive clusters.

This patch can improve read performance by reducing the number of
get_block calls in sequential read scenarios. speacially in small
cluster size.

According to my test data, the performance improvement is
approximately 10% when read FAT_CHAIN file with 512 bytes of
cluster size.

454 MB/s -> 511 MB/s

Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
 fs/exfat/cache.c    | 51 +++++++++++++++++++++++++++++++++++++++++----
 fs/exfat/exfat_fs.h |  2 +-
 fs/exfat/inode.c    |  5 +++--
 3 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c
index 57a66c067394..80efe2e0393d 100644
--- a/fs/exfat/cache.c
+++ b/fs/exfat/cache.c
@@ -234,7 +234,8 @@ static inline void cache_init(struct exfat_cache_id *cid,
 }
 
 int exfat_get_cluster(struct inode *inode, unsigned int cluster,
-		unsigned int *dclus, unsigned int *last_dclus)
+		unsigned int *dclus, unsigned int *count,
+		unsigned int *last_dclus)
 {
 	struct super_block *sb = inode->i_sb;
 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
@@ -243,6 +244,7 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 	struct buffer_head *bh = NULL;
 	struct exfat_cache_id cid;
 	unsigned int content, fclus;
+	unsigned int end = (*count <= 1) ? cluster : cluster + *count - 1;
 
 	if (ei->start_clu == EXFAT_FREE_CLUSTER) {
 		exfat_fs_error(sb,
@@ -256,17 +258,33 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 	*last_dclus = *dclus;
 
 	/*
-	 * Don`t use exfat_cache if zero offset or non-cluster allocation
+	 * This case should not exist, as exfat_map_cluster function doesn't
+	 * call this routine when start_clu == EXFAT_EOF_CLUSTER.
+	 * This case is retained here for routine completeness.
 	 */
-	if (cluster == 0 || *dclus == EXFAT_EOF_CLUSTER)
+	if (*dclus == EXFAT_EOF_CLUSTER) {
+		*count = 0;
+		return 0;
+	}
+
+	/* If only the first cluster is needed, return now. */
+	if (fclus == cluster && *count == 1)
 		return 0;
 
 	cache_init(&cid, fclus, *dclus);
 	exfat_cache_lookup(inode, cluster, &cid, &fclus, dclus);
 
-	if (fclus == cluster)
+	/*
+	 * Return on cache hit to keep the code simple.
+	 */
+	if (fclus == cluster) {
+		*count = cid.fcluster + cid.nr_contig - fclus + 1;
 		return 0;
+	}
 
+	/*
+	 * Find the first cluster we need.
+	 */
 	while (fclus < cluster) {
 		/* prevent the infinite loop of cluster chain */
 		if (fclus > limit) {
@@ -290,6 +308,31 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 			cache_init(&cid, fclus, *dclus);
 	}
 
+	/*
+	 * Collect the remaining clusters of this contiguous extent.
+	 */
+	if (*dclus != EXFAT_EOF_CLUSTER) {
+		unsigned int clu = *dclus;
+
+		/*
+		 * Now the cid cache contains the first cluster requested,
+		 * Advance the fclus to the last cluster of contiguous
+		 * extent, then update the count and cid cache accordingly.
+		 */
+		while (fclus < end) {
+			if (exfat_ent_get(sb, clu, &content, &bh))
+				goto err;
+			if (++clu != content) {
+				/* TODO: read ahead if content valid */
+				break;
+			}
+			fclus++;
+		}
+		cid.nr_contig = fclus - cid.fcluster;
+		*count = fclus - cluster + 1;
+	} else {
+		*count = 0;
+	}
 	brelse(bh);
 	exfat_cache_add(inode, &cid);
 	return 0;
diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index e58d8eed5495..2dbed5f8ec26 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -486,7 +486,7 @@ int exfat_cache_init(void);
 void exfat_cache_shutdown(void);
 void exfat_cache_inval_inode(struct inode *inode);
 int exfat_get_cluster(struct inode *inode, unsigned int cluster,
-		unsigned int *dclus, unsigned int *last_dclus);
+		unsigned int *dclus, unsigned int *count, unsigned int *last_dclus);
 
 /* dir.c */
 extern const struct inode_operations exfat_dir_inode_operations;
diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
index 8c49ab15eafe..317bc363f7d9 100644
--- a/fs/exfat/inode.c
+++ b/fs/exfat/inode.c
@@ -134,6 +134,7 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
 	struct exfat_inode_info *ei = EXFAT_I(inode);
 	unsigned int local_clu_offset = clu_offset;
 	unsigned int num_to_be_allocated = 0, num_clusters;
+	unsigned int hint_count = max(*count, 1);
 
 	num_clusters = EXFAT_B_TO_CLU(exfat_ondisk_size(inode), sbi);
 
@@ -159,11 +160,11 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
 			*count = 0;
 		}
 	} else if (ei->type == TYPE_FILE) {
+		*count = hint_count;
 		int err = exfat_get_cluster(inode, clu_offset,
-				clu, &last_clu);
+				clu, count, &last_clu);
 		if (err)
 			return -EIO;
-		*count = (*clu == EXFAT_EOF_CLUSTER) ? 0 : 1;
 	} else {
 		unsigned int fclus = 0;
 		/* hint information */
-- 
2.43.0


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

* Re: [PATCH v1 9/9] exfat: support multi-cluster for exfat_get_cluster
  2026-01-06  7:32       ` Yuezhang.Mo
@ 2026-01-06  8:45         ` Chi Zhiling
  0 siblings, 0 replies; 16+ messages in thread
From: Chi Zhiling @ 2026-01-06  8:45 UTC (permalink / raw)
  To: Yuezhang.Mo
  Cc: brauner, chizhiling, jack, linkinjeon, linux-fsdevel,
	linux-kernel, sj1557.seo, viro, willy

On 1/6/26 15:32, Yuezhang.Mo@sony.com wrote:
>> On 1/4/26 15:56, Yuezhang.Mo@sony.com wrote:
>>>> On 12/30/25 17:06, Yuezhang.Mo@sony.com wrote:
>>>>>> +     /*
>>>>>> +      * Return on cache hit to keep the code simple.
>>>>>> +      */
>>>>>> +     if (fclus == cluster) {
>>>>>> +             *count = cid.fcluster + cid.nr_contig - fclus + 1;
>>>>>>                  return 0;
>>>>>
>>>>> If 'cid.fcluster + cid.nr_contig - fclus + 1 < *count', how about continuing to collect clusters?
>>>>> The following clusters may be continuous.
>>>>
>>>> I'm glad you noticed this detail. It is necessary to explain this and
>>>> update it in the code comments.
>>>>
>>>> The main reason why I didn't continue the collection was that the
>>>> subsequent clusters might also exist in the cache. This requires us to
>>>> search the cache again to confirm this, and this action might introduce
>>>> additional performance overhead.
>>>>
>>>> I think we can continue to collect, but we need to check the cache
>>>> before doing so.
>>>>
>>>
>>> So we also need to check the cache in the following, right?
>>
>> Uh, I don't think it's necessary in here, because these clusters won't
>> exist in the cache.
>>
>> In the cache_lru, all exfat_cache start from non-continuous clusters.
>> This is because exfat_get_cluster adds consecutive clusters to the cache
>> from left to right, which means that the left side of all caches is
>> non-continuous.
>>
>> For instance, if a file contains two extents,  [0,30] and [31,60], then
>> exfat_cache must start at either 0 or 31, right?
>>
>> When we have found a cache is [31, 45], then there won't be [41, 60] in
>> the cache_lru.
>>
>> So when we already get some head clusters of a continuous extent, the
>> tail cluster will definitely not be present in the cache.
>>
> 
> Your understanding is correct, so if the cache only includes a part of the
> requested clusters, we can continue to collect subsequent clusters.
> 
>>
>> ---
>>
>> Here are some modifications regarding this patch (which may be reflected
>> in the V2 version). Do you have any thoughts or suggestions on this?
>>
> 
> Although these modifications make exfat_cache_lookup check the entire
> cache every time, I think the modifications are reasonable since the cache
> (EXFAT_MAX_CACHE is 16) is small.

I have improved it in v2. :)

> 
>>
>> diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c
>> index 1ec531859944..8ff416beea3c 100644
>> --- a/fs/exfat/cache.c
>> +++ b/fs/exfat/cache.c
>> @@ -80,6 +80,10 @@ static inline void exfat_cache_update_lru(struct
>> inode *inode,
>>                   list_move(&cache->cache_list, &ei->cache_lru);
>>    }
>>
>> +/*
>> + * Return fcluster of the cache which behind fclus, or
>> + * EXFAT_EOF_CLUSTER if no cache in there.
>> + */
>>    static bool exfat_cache_lookup(struct inode *inode,
>>                   unsigned int fclus, struct exfat_cache_id *cid,
>>                   unsigned int *cached_fclus, unsigned int *cached_dclus)
>> @@ -87,6 +91,7 @@ static bool exfat_cache_lookup(struct inode *inode,
>>           struct exfat_inode_info *ei = EXFAT_I(inode);
>>           static struct exfat_cache nohit = { .fcluster = 0, };
>>           struct exfat_cache *hit = &nohit, *p;
>> +       unsigned int next = EXFAT_EOF_CLUSTER;
>>           unsigned int offset;
>>
>>           spin_lock(&ei->cache_lru_lock);
>> @@ -98,8 +103,9 @@ static bool exfat_cache_lookup(struct inode *inode,
>>                                   offset = hit->nr_contig;
>>                           } else {
>>                                   offset = fclus - hit->fcluster;
>> -                               break;
>>                           }
>> +               } else if (p->fcluster > fclus && p->fcluster < next) {
>> +                       next = p->fcluster;
>>                   }
>>           }
>>           if (hit != &nohit) {
>> @@ -114,7 +120,7 @@ static bool exfat_cache_lookup(struct inode *inode,
>>           }
>>           spin_unlock(&ei->cache_lru_lock);
>>
>> -       return hit != &nohit;
>> +       return next;
>>    }
>>
>>    static struct exfat_cache *exfat_cache_merge(struct inode *inode,
>> @@ -243,7 +249,7 @@ int exfat_get_cluster(struct inode *inode, unsigned
>> int cluster,
>>           struct exfat_inode_info *ei = EXFAT_I(inode);
>>           struct buffer_head *bh = NULL;
>>           struct exfat_cache_id cid;
>> -       unsigned int content, fclus;
>> +       unsigned int content, fclus, next;
>>           unsigned int end = cluster + *count - 1;
>>
>>           if (ei->start_clu == EXFAT_FREE_CLUSTER) {
>> @@ -272,14 +278,15 @@ int exfat_get_cluster(struct inode *inode,
>> unsigned int cluster,
>>                   return 0;
>>
>>           cache_init(&cid, fclus, *dclus);
>> -       exfat_cache_lookup(inode, cluster, &cid, &fclus, dclus);
>> +       next = exfat_cache_lookup(inode, cluster, &cid, &fclus, dclus);
>>
>> -       /*
>> -        * Return on cache hit to keep the code simple.
>> -        */
>>           if (fclus == cluster) {
>> -               *count = cid.fcluster + cid.nr_contig - fclus + 1;
> 
> If the cache only includes a part of the requested clusters and subsequent
> clusters are not contiguous. '*count' is needed to set like above.

You are right, I will fix it in v2.

Thanks,

> 
>> -               return 0;
>> +               /* The cache includes all cluster requested */
>> +               if (cid.fcluster + cid.nr_contig >= end)
>> +                       return 0;
>> +               /* No cache hole behind this cache */
>> +               if (next == cid.fcluster + cid.nr_contig + 1)
>> +                       return 0;
>>           }
>>
>>           /*
>>
>>
>> Thanks,
>>
>>>
>>> ```
>>>           /*
>>>            * Collect the remaining clusters of this contiguous extent.
>>>            */
>>>           if (*dclus != EXFAT_EOF_CLUSTER) {
>>>                   unsigned int clu = *dclus;
>>>
>>>                   /*
>>>                    * Now the cid cache contains the first cluster requested,
>>>                    * Advance the fclus to the last cluster of contiguous
>>>                    * extent, then update the count and cid cache accordingly.
>>>                    */
>>>                   while (fclus < end) {
>>>                           if (exfat_ent_get(sb, clu, &content, &bh))
>>>                                   goto err;
>>>                           if (++clu != content) {
>>>                                   /* TODO: read ahead if content valid */
>>>                                   break;
>>>                           }
>>>                           fclus++;
>>>                   }
>>>                   cid.nr_contig = fclus - cid.fcluster;
>>>                   *count = fclus - cluster + 1;
>>> ```
>>>
>>>>>>
>>>>>> +             while (fclus < end) {
>>>>>> +                     if (exfat_ent_get(sb, clu, &content, &bh))
>>>>>> +                             goto err;
>>>>>> +                     if (++clu != content) {
>>>>>> +                             /* TODO: read ahead if content valid */
>>>>>> +                             break;
>>>>>
>>>>> The next cluster index has been read and will definitely be used.
>>>>> How about add it to the cache?
>>>>
>>>> Good idea!
>>>> will add it in v2,


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

* Re: [PATCH v1 9/9] exfat: support multi-cluster for exfat_get_cluster
  2026-01-05  2:58     ` Chi Zhiling
@ 2026-01-06  7:32       ` Yuezhang.Mo
  2026-01-06  8:45         ` Chi Zhiling
  0 siblings, 1 reply; 16+ messages in thread
From: Yuezhang.Mo @ 2026-01-06  7:32 UTC (permalink / raw)
  To: Chi Zhiling
  Cc: brauner, chizhiling, jack, linkinjeon, linux-fsdevel,
	linux-kernel, sj1557.seo, viro, willy

> On 1/4/26 15:56, Yuezhang.Mo@sony.com wrote:
>>> On 12/30/25 17:06, Yuezhang.Mo@sony.com wrote:
>>>>> +     /*
>>>>> +      * Return on cache hit to keep the code simple.
>>>>> +      */
>>>>> +     if (fclus == cluster) {
>>>>> +             *count = cid.fcluster + cid.nr_contig - fclus + 1;
>>>>>                 return 0;
>>>>
>>>> If 'cid.fcluster + cid.nr_contig - fclus + 1 < *count', how about continuing to collect clusters?
>>>> The following clusters may be continuous.
>>>
>>> I'm glad you noticed this detail. It is necessary to explain this and
>>> update it in the code comments.
>>>
>>> The main reason why I didn't continue the collection was that the
>>> subsequent clusters might also exist in the cache. This requires us to
>>> search the cache again to confirm this, and this action might introduce
>>> additional performance overhead.
>>>
>>> I think we can continue to collect, but we need to check the cache
>>> before doing so.
>>>
>>
>> So we also need to check the cache in the following, right?
>
> Uh, I don't think it's necessary in here, because these clusters won't
> exist in the cache.
> 
> In the cache_lru, all exfat_cache start from non-continuous clusters.
> This is because exfat_get_cluster adds consecutive clusters to the cache
> from left to right, which means that the left side of all caches is
> non-continuous.
> 
> For instance, if a file contains two extents,  [0,30] and [31,60], then
> exfat_cache must start at either 0 or 31, right?
> 
> When we have found a cache is [31, 45], then there won't be [41, 60] in
> the cache_lru.
> 
> So when we already get some head clusters of a continuous extent, the
> tail cluster will definitely not be present in the cache.
> 

Your understanding is correct, so if the cache only includes a part of the
requested clusters, we can continue to collect subsequent clusters.

> 
> ---
> 
> Here are some modifications regarding this patch (which may be reflected
> in the V2 version). Do you have any thoughts or suggestions on this?
> 

Although these modifications make exfat_cache_lookup check the entire
cache every time, I think the modifications are reasonable since the cache
(EXFAT_MAX_CACHE is 16) is small.

> 
> diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c
> index 1ec531859944..8ff416beea3c 100644
> --- a/fs/exfat/cache.c
> +++ b/fs/exfat/cache.c
> @@ -80,6 +80,10 @@ static inline void exfat_cache_update_lru(struct
> inode *inode,
>                  list_move(&cache->cache_list, &ei->cache_lru);
>   }
> 
> +/*
> + * Return fcluster of the cache which behind fclus, or
> + * EXFAT_EOF_CLUSTER if no cache in there.
> + */
>   static bool exfat_cache_lookup(struct inode *inode,
>                  unsigned int fclus, struct exfat_cache_id *cid,
>                  unsigned int *cached_fclus, unsigned int *cached_dclus)
> @@ -87,6 +91,7 @@ static bool exfat_cache_lookup(struct inode *inode,
>          struct exfat_inode_info *ei = EXFAT_I(inode);
>          static struct exfat_cache nohit = { .fcluster = 0, };
>          struct exfat_cache *hit = &nohit, *p;
> +       unsigned int next = EXFAT_EOF_CLUSTER;
>          unsigned int offset;
> 
>          spin_lock(&ei->cache_lru_lock);
> @@ -98,8 +103,9 @@ static bool exfat_cache_lookup(struct inode *inode,
>                                  offset = hit->nr_contig;
>                          } else {
>                                  offset = fclus - hit->fcluster;
> -                               break;
>                          }
> +               } else if (p->fcluster > fclus && p->fcluster < next) {
> +                       next = p->fcluster;
>                  }
>          }
>          if (hit != &nohit) {
> @@ -114,7 +120,7 @@ static bool exfat_cache_lookup(struct inode *inode,
>          }
>          spin_unlock(&ei->cache_lru_lock);
> 
> -       return hit != &nohit;
> +       return next;
>   }
> 
>   static struct exfat_cache *exfat_cache_merge(struct inode *inode,
> @@ -243,7 +249,7 @@ int exfat_get_cluster(struct inode *inode, unsigned
> int cluster,
>          struct exfat_inode_info *ei = EXFAT_I(inode);
>          struct buffer_head *bh = NULL;
>          struct exfat_cache_id cid;
> -       unsigned int content, fclus;
> +       unsigned int content, fclus, next;
>          unsigned int end = cluster + *count - 1;
> 
>          if (ei->start_clu == EXFAT_FREE_CLUSTER) {
> @@ -272,14 +278,15 @@ int exfat_get_cluster(struct inode *inode,
> unsigned int cluster,
>                  return 0;
> 
>          cache_init(&cid, fclus, *dclus);
> -       exfat_cache_lookup(inode, cluster, &cid, &fclus, dclus);
> +       next = exfat_cache_lookup(inode, cluster, &cid, &fclus, dclus);
> 
> -       /*
> -        * Return on cache hit to keep the code simple.
> -        */
>          if (fclus == cluster) {
> -               *count = cid.fcluster + cid.nr_contig - fclus + 1;

If the cache only includes a part of the requested clusters and subsequent
clusters are not contiguous. '*count' is needed to set like above.

> -               return 0;
> +               /* The cache includes all cluster requested */
> +               if (cid.fcluster + cid.nr_contig >= end)
> +                       return 0;
> +               /* No cache hole behind this cache */
> +               if (next == cid.fcluster + cid.nr_contig + 1)
> +                       return 0;
>          }
> 
>          /*
> 
> 
> Thanks,
> 
>>
>> ```
>>          /*
>>           * Collect the remaining clusters of this contiguous extent.
>>           */
>>          if (*dclus != EXFAT_EOF_CLUSTER) {
>>                  unsigned int clu = *dclus;
>>
>>                  /*
>>                   * Now the cid cache contains the first cluster requested,
>>                   * Advance the fclus to the last cluster of contiguous
>>                   * extent, then update the count and cid cache accordingly.
>>                   */
>>                  while (fclus < end) {
>>                          if (exfat_ent_get(sb, clu, &content, &bh))
>>                                  goto err;
>>                          if (++clu != content) {
>>                                  /* TODO: read ahead if content valid */
>>                                  break;
>>                          }
>>                          fclus++;
>>                  }
>>                  cid.nr_contig = fclus - cid.fcluster;
>>                  *count = fclus - cluster + 1;
>> ```
>>
>>>>>
>>>>> +             while (fclus < end) {
>>>>> +                     if (exfat_ent_get(sb, clu, &content, &bh))
>>>>> +                             goto err;
>>>>> +                     if (++clu != content) {
>>>>> +                             /* TODO: read ahead if content valid */
>>>>> +                             break;
>>>>
>>>> The next cluster index has been read and will definitely be used.
>>>> How about add it to the cache?
>>>
>>> Good idea!
>>> will add it in v2,

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

* Re: [PATCH v1 9/9] exfat: support multi-cluster for exfat_get_cluster
  2026-01-04  7:56   ` Yuezhang.Mo
@ 2026-01-05  2:58     ` Chi Zhiling
  2026-01-06  7:32       ` Yuezhang.Mo
  0 siblings, 1 reply; 16+ messages in thread
From: Chi Zhiling @ 2026-01-05  2:58 UTC (permalink / raw)
  To: Yuezhang.Mo
  Cc: brauner, chizhiling, jack, linkinjeon, linux-fsdevel,
	linux-kernel, sj1557.seo, viro, willy

On 1/4/26 15:56, Yuezhang.Mo@sony.com wrote:
>> On 12/30/25 17:06, Yuezhang.Mo@sony.com wrote:
>>>> +     /*
>>>> +      * Return on cache hit to keep the code simple.
>>>> +      */
>>>> +     if (fclus == cluster) {
>>>> +             *count = cid.fcluster + cid.nr_contig - fclus + 1;
>>>>                 return 0;
>>>
>>> If 'cid.fcluster + cid.nr_contig - fclus + 1 < *count', how about continuing to collect clusters?
>>> The following clusters may be continuous.
>>
>> I'm glad you noticed this detail. It is necessary to explain this and
>> update it in the code comments.
>>
>> The main reason why I didn't continue the collection was that the
>> subsequent clusters might also exist in the cache. This requires us to
>> search the cache again to confirm this, and this action might introduce
>> additional performance overhead.
>>
>> I think we can continue to collect, but we need to check the cache
>> before doing so.
>>
> 
> So we also need to check the cache in the following, right?

Uh, I don't think it's necessary in here, because these clusters won't 
exist in the cache.

In the cache_lru, all exfat_cache start from non-continuous clusters. 
This is because exfat_get_cluster adds consecutive clusters to the cache 
from left to right, which means that the left side of all caches is 
non-continuous.

For instance, if a file contains two extents,  [0,30] and [31,60], then 
exfat_cache must start at either 0 or 31, right?

When we have found a cache is [31, 45], then there won't be [41, 60] in 
the cache_lru.

So when we already get some head clusters of a continuous extent, the 
tail cluster will definitely not be present in the cache.


---

Here are some modifications regarding this patch (which may be reflected 
in the V2 version). Do you have any thoughts or suggestions on this?


diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c
index 1ec531859944..8ff416beea3c 100644
--- a/fs/exfat/cache.c
+++ b/fs/exfat/cache.c
@@ -80,6 +80,10 @@ static inline void exfat_cache_update_lru(struct 
inode *inode,
                 list_move(&cache->cache_list, &ei->cache_lru);
  }

+/*
+ * Return fcluster of the cache which behind fclus, or
+ * EXFAT_EOF_CLUSTER if no cache in there.
+ */
  static bool exfat_cache_lookup(struct inode *inode,
                 unsigned int fclus, struct exfat_cache_id *cid,
                 unsigned int *cached_fclus, unsigned int *cached_dclus)
@@ -87,6 +91,7 @@ static bool exfat_cache_lookup(struct inode *inode,
         struct exfat_inode_info *ei = EXFAT_I(inode);
         static struct exfat_cache nohit = { .fcluster = 0, };
         struct exfat_cache *hit = &nohit, *p;
+       unsigned int next = EXFAT_EOF_CLUSTER;
         unsigned int offset;

         spin_lock(&ei->cache_lru_lock);
@@ -98,8 +103,9 @@ static bool exfat_cache_lookup(struct inode *inode,
                                 offset = hit->nr_contig;
                         } else {
                                 offset = fclus - hit->fcluster;
-                               break;
                         }
+               } else if (p->fcluster > fclus && p->fcluster < next) {
+                       next = p->fcluster;
                 }
         }
         if (hit != &nohit) {
@@ -114,7 +120,7 @@ static bool exfat_cache_lookup(struct inode *inode,
         }
         spin_unlock(&ei->cache_lru_lock);

-       return hit != &nohit;
+       return next;
  }

  static struct exfat_cache *exfat_cache_merge(struct inode *inode,
@@ -243,7 +249,7 @@ int exfat_get_cluster(struct inode *inode, unsigned 
int cluster,
         struct exfat_inode_info *ei = EXFAT_I(inode);
         struct buffer_head *bh = NULL;
         struct exfat_cache_id cid;
-       unsigned int content, fclus;
+       unsigned int content, fclus, next;
         unsigned int end = cluster + *count - 1;

         if (ei->start_clu == EXFAT_FREE_CLUSTER) {
@@ -272,14 +278,15 @@ int exfat_get_cluster(struct inode *inode, 
unsigned int cluster,
                 return 0;

         cache_init(&cid, fclus, *dclus);
-       exfat_cache_lookup(inode, cluster, &cid, &fclus, dclus);
+       next = exfat_cache_lookup(inode, cluster, &cid, &fclus, dclus);

-       /*
-        * Return on cache hit to keep the code simple.
-        */
         if (fclus == cluster) {
-               *count = cid.fcluster + cid.nr_contig - fclus + 1;
-               return 0;
+               /* The cache includes all cluster requested */
+               if (cid.fcluster + cid.nr_contig >= end)
+                       return 0;
+               /* No cache hole behind this cache */
+               if (next == cid.fcluster + cid.nr_contig + 1)
+                       return 0;
         }

         /*


Thanks,

> 
> ```
>          /*
>           * Collect the remaining clusters of this contiguous extent.
>           */
>          if (*dclus != EXFAT_EOF_CLUSTER) {
>                  unsigned int clu = *dclus;
> 
>                  /*
>                   * Now the cid cache contains the first cluster requested,
>                   * Advance the fclus to the last cluster of contiguous
>                   * extent, then update the count and cid cache accordingly.
>                   */
>                  while (fclus < end) {
>                          if (exfat_ent_get(sb, clu, &content, &bh))
>                                  goto err;
>                          if (++clu != content) {
>                                  /* TODO: read ahead if content valid */
>                                  break;
>                          }
>                          fclus++;
>                  }
>                  cid.nr_contig = fclus - cid.fcluster;
>                  *count = fclus - cluster + 1;
> ```
> 
>>>>
>>>> +             while (fclus < end) {
>>>> +                     if (exfat_ent_get(sb, clu, &content, &bh))
>>>> +                             goto err;
>>>> +                     if (++clu != content) {
>>>> +                             /* TODO: read ahead if content valid */
>>>> +                             break;
>>>
>>> The next cluster index has been read and will definitely be used.
>>> How about add it to the cache?
>>
>> Good idea!
>> will add it in v2,


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

* Re: [PATCH v1 9/9] exfat: support multi-cluster for exfat_get_cluster
  2025-12-31  2:35 ` Chi Zhiling
@ 2026-01-04  7:56   ` Yuezhang.Mo
  2026-01-05  2:58     ` Chi Zhiling
  0 siblings, 1 reply; 16+ messages in thread
From: Yuezhang.Mo @ 2026-01-04  7:56 UTC (permalink / raw)
  To: Chi Zhiling
  Cc: brauner, chizhiling, jack, linkinjeon, linux-fsdevel,
	linux-kernel, sj1557.seo, viro, willy

> On 12/30/25 17:06, Yuezhang.Mo@sony.com wrote:
>>> +     /*
>>> +      * Return on cache hit to keep the code simple.
>>> +      */
>>> +     if (fclus == cluster) {
>>> +             *count = cid.fcluster + cid.nr_contig - fclus + 1;
>>>                return 0;
>>
>> If 'cid.fcluster + cid.nr_contig - fclus + 1 < *count', how about continuing to collect clusters?
>> The following clusters may be continuous.
>
> I'm glad you noticed this detail. It is necessary to explain this and
> update it in the code comments.
> 
> The main reason why I didn't continue the collection was that the
> subsequent clusters might also exist in the cache. This requires us to
> search the cache again to confirm this, and this action might introduce
> additional performance overhead.
> 
> I think we can continue to collect, but we need to check the cache
> before doing so.
>

So we also need to check the cache in the following, right?

```
        /*
         * Collect the remaining clusters of this contiguous extent.
         */
        if (*dclus != EXFAT_EOF_CLUSTER) {
                unsigned int clu = *dclus;

                /*
                 * Now the cid cache contains the first cluster requested,
                 * Advance the fclus to the last cluster of contiguous
                 * extent, then update the count and cid cache accordingly.
                 */
                while (fclus < end) {
                        if (exfat_ent_get(sb, clu, &content, &bh))
                                goto err;
                        if (++clu != content) {
                                /* TODO: read ahead if content valid */
                                break;
                        }
                        fclus++;
                }
                cid.nr_contig = fclus - cid.fcluster;
                *count = fclus - cluster + 1;
```

>>>
>>> +             while (fclus < end) {
>>> +                     if (exfat_ent_get(sb, clu, &content, &bh))
>>> +                             goto err;
>>> +                     if (++clu != content) {
>>> +                             /* TODO: read ahead if content valid */
>>> +                             break;
>>
>> The next cluster index has been read and will definitely be used.
>> How about add it to the cache?
>
> Good idea!
> will add it in v2,

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

* Re: [PATCH v1 9/9] exfat: support multi-cluster for exfat_get_cluster
  2025-12-30  9:06 Yuezhang.Mo
@ 2025-12-31  2:35 ` Chi Zhiling
  2026-01-04  7:56   ` Yuezhang.Mo
  0 siblings, 1 reply; 16+ messages in thread
From: Chi Zhiling @ 2025-12-31  2:35 UTC (permalink / raw)
  To: Yuezhang.Mo
  Cc: brauner, chizhiling, jack, linkinjeon, linux-fsdevel,
	linux-kernel, sj1557.seo, viro, willy

On 12/30/25 17:06, Yuezhang.Mo@sony.com wrote:
>> @@ -243,6 +244,7 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
>>        struct buffer_head *bh = NULL;
>>        struct exfat_cache_id cid;
>>        unsigned int content, fclus;
>> +     unsigned int end = (*count <= 1) ? cluster : cluster + *count - 1;
> 
> In exfat_get_block,  count is set as follows:
> 
> count = EXFAT_B_TO_CLU_ROUND_UP(bh_result->b_size, sbi);
> 
> So '*count' is always greater than or equal to 1, the above condition seems unnecessary.


Yes, it is unnecessary.

> 
>> --- a/fs/exfat/inode.c
>> +++ b/fs/exfat/inode.c
>> @@ -134,6 +134,7 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
>>        struct exfat_inode_info *ei = EXFAT_I(inode);
>>        unsigned int local_clu_offset = clu_offset;
>>        unsigned int num_to_be_allocated = 0, num_clusters;
>> +     unsigned int hint_count = max(*count, 1);
> 
> Same as above, hint_count seems unnecessary.
> 
>> +     /*
>> +      * Return on cache hit to keep the code simple.
>> +      */
>> +     if (fclus == cluster) {
>> +             *count = cid.fcluster + cid.nr_contig - fclus + 1;
>>                return 0;
> 
> If 'cid.fcluster + cid.nr_contig - fclus + 1 < *count', how about continuing to collect clusters?
> The following clusters may be continuous.

I'm glad you noticed this detail. It is necessary to explain this and 
update it in the code comments.

The main reason why I didn't continue the collection was that the 
subsequent clusters might also exist in the cache. This requires us to 
search the cache again to confirm this, and this action might introduce 
additional performance overhead.

I think we can continue to collect, but we need to check the cache 
before doing so.

> 
>> +             while (fclus < end) {
>> +                     if (exfat_ent_get(sb, clu, &content, &bh))
>> +                             goto err;
>> +                     if (++clu != content) {
>> +                             /* TODO: read ahead if content valid */
>> +                             break;
> 
> The next cluster index has been read and will definitely be used.
> How about add it to the cache?

Good idea!
will add it in v2,

thanks,

> 


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

* Re: [PATCH v1 9/9] exfat: support multi-cluster for exfat_get_cluster
@ 2025-12-30  9:06 Yuezhang.Mo
  2025-12-31  2:35 ` Chi Zhiling
  0 siblings, 1 reply; 16+ messages in thread
From: Yuezhang.Mo @ 2025-12-30  9:06 UTC (permalink / raw)
  To: chizhiling
  Cc: brauner, chizhiling, jack, linkinjeon, linux-fsdevel,
	linux-kernel, sj1557.seo, viro, willy

> @@ -243,6 +244,7 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
>       struct buffer_head *bh = NULL;
>       struct exfat_cache_id cid;
>       unsigned int content, fclus;
> +     unsigned int end = (*count <= 1) ? cluster : cluster + *count - 1;

In exfat_get_block,  count is set as follows:

count = EXFAT_B_TO_CLU_ROUND_UP(bh_result->b_size, sbi);

So '*count' is always greater than or equal to 1, the above condition seems unnecessary.

> --- a/fs/exfat/inode.c
> +++ b/fs/exfat/inode.c
> @@ -134,6 +134,7 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
>       struct exfat_inode_info *ei = EXFAT_I(inode);
>       unsigned int local_clu_offset = clu_offset;
>       unsigned int num_to_be_allocated = 0, num_clusters;
> +     unsigned int hint_count = max(*count, 1);

Same as above, hint_count seems unnecessary.

> +     /*
> +      * Return on cache hit to keep the code simple.
> +      */
> +     if (fclus == cluster) {
> +             *count = cid.fcluster + cid.nr_contig - fclus + 1;
>               return 0;

If 'cid.fcluster + cid.nr_contig - fclus + 1 < *count', how about continuing to collect clusters?
The following clusters may be continuous.

> +             while (fclus < end) {
> +                     if (exfat_ent_get(sb, clu, &content, &bh))
> +                             goto err;
> +                     if (++clu != content) {
> +                             /* TODO: read ahead if content valid */
> +                             break;

The next cluster index has been read and will definitely be used.
How about add it to the cache?


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

end of thread, other threads:[~2026-01-06  8:46 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-26  9:44 [PATCH v1 0/9] Enable exfat_get_block to support obtaining multiple clusters Chi Zhiling
2025-12-26  9:44 ` [PATCH v1 1/9] exfat: add cache option for __exfat_ent_get Chi Zhiling
2025-12-26  9:44 ` [PATCH v1 2/9] exfat: support reuse buffer head for exfat_ent_get Chi Zhiling
2025-12-26  9:44 ` [PATCH v1 3/9] exfat: reuse cache to improve exfat_get_cluster Chi Zhiling
2025-12-26  9:44 ` [PATCH v1 4/9] exfat: improve exfat_count_num_clusters Chi Zhiling
2025-12-26  9:44 ` [PATCH v1 5/9] exfat: improve exfat_find_last_cluster Chi Zhiling
2025-12-26  9:44 ` [PATCH v1 6/9] exfat: remove unused parameters from exfat_get_cluster Chi Zhiling
2025-12-26  9:44 ` [PATCH v1 7/9] exfat: tweak exfat_cache_lookup to support zero offset cluster Chi Zhiling
2025-12-26  9:44 ` [PATCH v1 8/9] exfat: support multi-cluster for exfat_map_cluster Chi Zhiling
2025-12-26  9:44 ` [PATCH v1 9/9] exfat: support multi-cluster for exfat_get_cluster Chi Zhiling
2025-12-30  9:06 Yuezhang.Mo
2025-12-31  2:35 ` Chi Zhiling
2026-01-04  7:56   ` Yuezhang.Mo
2026-01-05  2:58     ` Chi Zhiling
2026-01-06  7:32       ` Yuezhang.Mo
2026-01-06  8:45         ` Chi Zhiling

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®