]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
exfat: support reuse buffer head for exfat_ent_get
authorChi Zhiling <chizhiling@kylinos.cn>
Wed, 14 Jan 2026 12:12:38 +0000 (20:12 +0800)
committerNamjae Jeon <linkinjeon@kernel.org>
Thu, 12 Feb 2026 12:21:48 +0000 (21:21 +0900)
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>
Reviewed-by: Yuezhang Mo <Yuezhang.Mo@sony.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
fs/exfat/cache.c
fs/exfat/exfat_fs.h
fs/exfat/fatent.c

index d5ce0ae660ba4655b7be8f3c8904fcba05dfbb51..61af3fa05ab7383bef59b464e7e3c16a0e2593fc 100644 (file)
@@ -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;
index 176fef62574cf78435473c8b67806203ec13445f..f7f25e0600c7057d449edbfb1aff4dc88ac8610d 100644 (file)
@@ -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,
index 0cfbc0b435bd8bcd079e046a1a9ba4c53712bd6a..679688cfea015e37e2bb8998b3c781b3171ccf48 100644 (file)
@@ -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;