Skip to content

Commit 636bd62

Browse files
Chi Zhilingnamjaejeon
authored andcommitted
exfat: optimize exfat_chain_cont_cluster with cached buffer heads
When converting files from NO_FAT_CHAIN to FAT_CHAIN format, profiling reveals significant time spent in mark_buffer_dirty() and exfat_mirror_bh() operations. This overhead occurs because each FAT entry modification triggers a full block dirty marking and mirroring operation. For consecutive clusters that reside in the same block, optimize by caching the buffer head and performing dirty marking only once at the end of the block's modifications. Performance improvements for converting a 30GB file: | Cluster Size | Before Patch | After Patch | Speedup | |--------------|--------------|-------------|---------| | 512 bytes | 4.243s | 1.866s | 2.27x | | 4KB | 0.863s | 0.236s | 3.66x | | 32KB | 0.069s | 0.034s | 2.03x | | 256KB | 0.012s | 0.006s | 2.00x | Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
1 parent 63193eb commit 636bd62

1 file changed

Lines changed: 37 additions & 12 deletions

File tree

fs/exfat/fatent.c

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ static int exfat_mirror_bh(struct super_block *sb, struct buffer_head *bh)
3232
return err;
3333
}
3434

35+
static int exfat_end_bh(struct super_block *sb, struct buffer_head *bh)
36+
{
37+
int err;
38+
39+
exfat_update_bh(bh, sb->s_flags & SB_SYNCHRONOUS);
40+
err = exfat_mirror_bh(sb, bh);
41+
brelse(bh);
42+
43+
return err;
44+
}
45+
3546
static int __exfat_ent_get(struct super_block *sb, unsigned int loc,
3647
unsigned int *content, struct buffer_head **last)
3748
{
@@ -62,29 +73,40 @@ static int __exfat_ent_get(struct super_block *sb, unsigned int loc,
6273
return 0;
6374
}
6475

65-
int exfat_ent_set(struct super_block *sb, unsigned int loc,
66-
unsigned int content)
76+
static int __exfat_ent_set(struct super_block *sb, unsigned int loc,
77+
unsigned int content, struct buffer_head **cache)
6778
{
68-
unsigned int off;
6979
sector_t sec;
7080
__le32 *fat_entry;
71-
struct buffer_head *bh;
81+
struct buffer_head *bh = cache ? *cache : NULL;
82+
unsigned int off;
7283

7384
sec = FAT_ENT_OFFSET_SECTOR(sb, loc);
7485
off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc);
7586

76-
bh = sb_bread(sb, sec);
77-
if (!bh)
78-
return -EIO;
87+
if (!bh || bh->b_blocknr != sec || !buffer_uptodate(bh)) {
88+
if (bh)
89+
exfat_end_bh(sb, bh);
90+
bh = sb_bread(sb, sec);
91+
if (cache)
92+
*cache = bh;
93+
if (unlikely(!bh))
94+
return -EIO;
95+
}
7996

8097
fat_entry = (__le32 *)&(bh->b_data[off]);
8198
*fat_entry = cpu_to_le32(content);
82-
exfat_update_bh(bh, sb->s_flags & SB_SYNCHRONOUS);
83-
exfat_mirror_bh(sb, bh);
84-
brelse(bh);
99+
if (!cache)
100+
exfat_end_bh(sb, bh);
85101
return 0;
86102
}
87103

104+
int exfat_ent_set(struct super_block *sb, unsigned int loc,
105+
unsigned int content)
106+
{
107+
return __exfat_ent_set(sb, loc, content, NULL);
108+
}
109+
88110
/*
89111
* Caller must release the buffer_head if no error return.
90112
*/
@@ -170,6 +192,7 @@ int exfat_blk_readahead(struct super_block *sb, sector_t sec,
170192
int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain,
171193
unsigned int len)
172194
{
195+
struct buffer_head *bh = NULL;
173196
sector_t sec, end, ra;
174197
blkcnt_t ra_cnt = 0;
175198

@@ -183,14 +206,16 @@ int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain,
183206
sec = FAT_ENT_OFFSET_SECTOR(sb, chain);
184207
exfat_blk_readahead(sb, sec, &ra, &ra_cnt, end);
185208

186-
if (exfat_ent_set(sb, chain, chain + 1))
209+
if (__exfat_ent_set(sb, chain, chain + 1, &bh))
187210
return -EIO;
188211
chain++;
189212
len--;
190213
}
191214

192-
if (exfat_ent_set(sb, chain, EXFAT_EOF_CLUSTER))
215+
if (__exfat_ent_set(sb, chain, EXFAT_EOF_CLUSTER, &bh))
193216
return -EIO;
217+
218+
exfat_end_bh(sb, bh);
194219
return 0;
195220
}
196221

0 commit comments

Comments
 (0)