diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c index 4177a933e0be..a973aa4de57b 100644 --- a/fs/exfat/fatent.c +++ b/fs/exfat/fatent.c @@ -32,6 +32,17 @@ static int exfat_mirror_bh(struct super_block *sb, struct buffer_head *bh) return err; } +static int exfat_end_bh(struct super_block *sb, struct buffer_head *bh) +{ + int err; + + exfat_update_bh(bh, sb->s_flags & SB_SYNCHRONOUS); + err = exfat_mirror_bh(sb, bh); + brelse(bh); + + return err; +} + static int __exfat_ent_get(struct super_block *sb, unsigned int loc, unsigned int *content, struct buffer_head **last) { @@ -62,29 +73,40 @@ static int __exfat_ent_get(struct super_block *sb, unsigned int loc, return 0; } -int exfat_ent_set(struct super_block *sb, unsigned int loc, - unsigned int content) +static int __exfat_ent_set(struct super_block *sb, unsigned int loc, + unsigned int content, struct buffer_head **cache) { - unsigned int off; sector_t sec; __le32 *fat_entry; - struct buffer_head *bh; + struct buffer_head *bh = cache ? *cache : NULL; + unsigned int off; 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)) { + if (bh) + exfat_end_bh(sb, bh); + bh = sb_bread(sb, sec); + if (cache) + *cache = bh; + if (unlikely(!bh)) + return -EIO; + } fat_entry = (__le32 *)&(bh->b_data[off]); *fat_entry = cpu_to_le32(content); - exfat_update_bh(bh, sb->s_flags & SB_SYNCHRONOUS); - exfat_mirror_bh(sb, bh); - brelse(bh); + if (!cache) + exfat_end_bh(sb, bh); return 0; } +int exfat_ent_set(struct super_block *sb, unsigned int loc, + unsigned int content) +{ + return __exfat_ent_set(sb, loc, content, NULL); +} + /* * Caller must release the buffer_head if no error return. */ @@ -170,6 +192,7 @@ int exfat_blk_readahead(struct super_block *sb, sector_t sec, int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, unsigned int len) { + struct buffer_head *bh = NULL; sector_t sec, end, ra; blkcnt_t ra_cnt = 0; @@ -183,14 +206,16 @@ int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, sec = FAT_ENT_OFFSET_SECTOR(sb, chain); exfat_blk_readahead(sb, sec, &ra, &ra_cnt, end); - if (exfat_ent_set(sb, chain, chain + 1)) + if (__exfat_ent_set(sb, chain, chain + 1, &bh)) return -EIO; chain++; len--; } - if (exfat_ent_set(sb, chain, EXFAT_EOF_CLUSTER)) + if (__exfat_ent_set(sb, chain, EXFAT_EOF_CLUSTER, &bh)) return -EIO; + + exfat_end_bh(sb, bh); return 0; }