OSDN Git Service

exfat: Unify access to the boot sector
authorTetsuhiro Kohada <Kohada.Tetsuhiro@dc.MitsubishiElectric.co.jp>
Tue, 21 Apr 2020 01:58:58 +0000 (10:58 +0900)
committerNamjae Jeon <namjae.jeon@samsung.com>
Wed, 22 Apr 2020 11:14:05 +0000 (20:14 +0900)
Unify access to boot sector via 'sbi->pbr_bh'.
This fixes vol_flags inconsistency at read failed in fs_set_vol_flags(),
and buffer_head leak in __exfat_fill_super().

Signed-off-by: Tetsuhiro Kohada <Kohada.Tetsuhiro@dc.MitsubishiElectric.co.jp>
Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
fs/exfat/balloc.c
fs/exfat/super.c

index 6a04cc0..6774a5a 100644 (file)
@@ -91,7 +91,6 @@ static int exfat_allocate_bitmap(struct super_block *sb,
                }
        }
 
-       sbi->pbr_bh = NULL;
        return 0;
 }
 
@@ -137,8 +136,6 @@ void exfat_free_bitmap(struct exfat_sb_info *sbi)
 {
        int i;
 
-       brelse(sbi->pbr_bh);
-
        for (i = 0; i < sbi->map_sectors; i++)
                __brelse(sbi->vol_amap[i]);
 
index 86c8756..6b63e50 100644 (file)
@@ -49,6 +49,7 @@ static void exfat_put_super(struct super_block *sb)
                sync_blockdev(sb->s_bdev);
        exfat_set_vol_flags(sb, VOL_CLEAN);
        exfat_free_bitmap(sbi);
+       brelse(sbi->pbr_bh);
        mutex_unlock(&sbi->s_lock);
 
        call_rcu(&sbi->rcu, exfat_delayed_free);
@@ -100,7 +101,7 @@ static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf)
 int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag)
 {
        struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       struct pbr64 *bpb;
+       struct pbr64 *bpb = (struct pbr64 *)sbi->pbr_bh->b_data;
        bool sync = 0;
 
        /* flags are not changed */
@@ -115,15 +116,6 @@ int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag)
        if (sb_rdonly(sb))
                return 0;
 
-       if (!sbi->pbr_bh) {
-               sbi->pbr_bh = sb_bread(sb, 0);
-               if (!sbi->pbr_bh) {
-                       exfat_msg(sb, KERN_ERR, "failed to read boot sector");
-                       return -ENOMEM;
-               }
-       }
-
-       bpb = (struct pbr64 *)sbi->pbr_bh->b_data;
        bpb->bsx.vol_flags = cpu_to_le16(new_flag);
 
        if (new_flag == VOL_DIRTY && !buffer_dirty(sbi->pbr_bh))
@@ -355,10 +347,10 @@ static int exfat_read_root(struct inode *inode)
        return 0;
 }
 
-static struct pbr *exfat_read_pbr_with_logical_sector(struct super_block *sb,
-               struct buffer_head **prev_bh)
+static struct pbr *exfat_read_pbr_with_logical_sector(struct super_block *sb)
 {
-       struct pbr *p_pbr = (struct pbr *) (*prev_bh)->b_data;
+       struct exfat_sb_info *sbi = EXFAT_SB(sb);
+       struct pbr *p_pbr = (struct pbr *) (sbi->pbr_bh)->b_data;
        unsigned short logical_sect = 0;
 
        logical_sect = 1 << p_pbr->bsx.f64.sect_size_bits;
@@ -378,26 +370,23 @@ static struct pbr *exfat_read_pbr_with_logical_sector(struct super_block *sb,
        }
 
        if (logical_sect > sb->s_blocksize) {
-               struct buffer_head *bh = NULL;
-
-               __brelse(*prev_bh);
-               *prev_bh = NULL;
+               brelse(sbi->pbr_bh);
+               sbi->pbr_bh = NULL;
 
                if (!sb_set_blocksize(sb, logical_sect)) {
                        exfat_msg(sb, KERN_ERR,
                                "unable to set blocksize %u", logical_sect);
                        return NULL;
                }
-               bh = sb_bread(sb, 0);
-               if (!bh) {
+               sbi->pbr_bh = sb_bread(sb, 0);
+               if (!sbi->pbr_bh) {
                        exfat_msg(sb, KERN_ERR,
                                "unable to read boot sector (logical sector size = %lu)",
                                sb->s_blocksize);
                        return NULL;
                }
 
-               *prev_bh = bh;
-               p_pbr = (struct pbr *) bh->b_data;
+               p_pbr = (struct pbr *)sbi->pbr_bh->b_data;
        }
        return p_pbr;
 }
@@ -408,21 +397,20 @@ static int __exfat_fill_super(struct super_block *sb)
        int ret;
        struct pbr *p_pbr;
        struct pbr64 *p_bpb;
-       struct buffer_head *bh;
        struct exfat_sb_info *sbi = EXFAT_SB(sb);
 
        /* set block size to read super block */
        sb_min_blocksize(sb, 512);
 
        /* read boot sector */
-       bh = sb_bread(sb, 0);
-       if (!bh) {
+       sbi->pbr_bh = sb_bread(sb, 0);
+       if (!sbi->pbr_bh) {
                exfat_msg(sb, KERN_ERR, "unable to read boot sector");
                return -EIO;
        }
 
        /* PRB is read */
-       p_pbr = (struct pbr *)bh->b_data;
+       p_pbr = (struct pbr *)sbi->pbr_bh->b_data;
 
        /* check the validity of PBR */
        if (le16_to_cpu((p_pbr->signature)) != PBR_SIGNATURE) {
@@ -433,7 +421,7 @@ static int __exfat_fill_super(struct super_block *sb)
 
 
        /* check logical sector size */
-       p_pbr = exfat_read_pbr_with_logical_sector(sb, &bh);
+       p_pbr = exfat_read_pbr_with_logical_sector(sb);
        if (!p_pbr) {
                ret = -EIO;
                goto free_bh;
@@ -514,7 +502,7 @@ free_alloc_bitmap:
 free_upcase_table:
        exfat_free_upcase_table(sbi);
 free_bh:
-       brelse(bh);
+       brelse(sbi->pbr_bh);
        return ret;
 }
 
@@ -606,6 +594,7 @@ put_inode:
 free_table:
        exfat_free_upcase_table(sbi);
        exfat_free_bitmap(sbi);
+       brelse(sbi->pbr_bh);
 
 check_nls_io:
        unload_nls(sbi->nls_io);