[PATCH 3/5] staging: exfat: consolidate boot sector analysis

From: Tetsuhiro Kohada
Date: Wed Mar 11 2020 - 06:52:55 EST


Consolidate boot sector analysis into read_boot_sector().

- Move boot sector analysis from exfat_mount() to read_boot_sector().
- Fix num_fats check in read_boot_sector().
- Consolidate p_fs->boot_bh initialization/release into mount/umount.

This fixes vol_flags inconsistency at read failed in fs_set_vol_flags(),
and tmp_bh leak in exfat_mount(). :-)

Reviewed-by: Takahiro Mori <Mori.Takahiro@xxxxxxxxxxxxxxxxxxxxxxxxxxx>
Signed-off-by: Tetsuhiro Kohada <Kohada.Tetsuhiro@xxxxxxxxxxxxxxxxxxxxxxxxxxx>
---
drivers/staging/exfat/exfat_core.c | 106 ++++++++++++-----------------
1 file changed, 45 insertions(+), 61 deletions(-)

diff --git a/drivers/staging/exfat/exfat_core.c b/drivers/staging/exfat/exfat_core.c
index 2d88ce85217c..3faa7f35c77c 100644
--- a/drivers/staging/exfat/exfat_core.c
+++ b/drivers/staging/exfat/exfat_core.c
@@ -89,11 +89,6 @@ void fs_set_vol_flags(struct super_block *sb, u32 new_flag)

p_fs->vol_flag = new_flag;

- if (!p_fs->boot_bh) {
- if (sector_read(sb, 0, &p_fs->boot_bh, 1) != 0)
- return;
- }
-
p_boot = (struct boot_sector_t *)p_fs->boot_bh->b_data;
p_boot->vol_flags = cpu_to_le16(new_flag);

@@ -531,8 +526,6 @@ static s32 load_alloc_bitmap(struct super_block *sb)
return ret;
}
}
-
- p_fs->boot_bh = NULL;
return 0;
}
}
@@ -549,9 +542,7 @@ static void free_alloc_bitmap(struct super_block *sb)
int i;
struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);

- brelse(p_fs->boot_bh);
-
- for (i = 0; i < p_fs->map_sectors; i++)
+ for (i = 0; i < p_fs->map_sectors && p_fs->vol_amap; i++)
__brelse(p_fs->vol_amap[i]);

kfree(p_fs->vol_amap);
@@ -763,7 +754,7 @@ static void free_upcase_table(struct super_block *sb)
u16 **upcase_table;

upcase_table = p_fs->vol_utbl;
- for (i = 0; i < UTBL_COL_COUNT; i++)
+ for (i = 0; i < UTBL_COL_COUNT && upcase_table; i++)
kfree(upcase_table[i]);

kfree(p_fs->vol_utbl);
@@ -2062,15 +2053,31 @@ s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir,
return 0;
}

-static s32 read_boot_sector(struct super_block *sb,
- struct boot_sector_t *p_boot)
+static int read_boot_sector(struct super_block *sb)
{
struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+ struct boot_sector_t *p_boot;
+ int i;
+
+ p_boot = (struct boot_sector_t *)p_fs->boot_bh->b_data;

- if (p_boot->num_fats == 0)
+ /* check the validity of BOOT sector */
+ if (le16_to_cpu(p_boot->boot_signature) != BOOT_SIGNATURE)
return -EFSCORRUPTED;

+ /* check the byte range consumed as BPB for FAT12/16/32 volumes */
+ for (i = 0; i < 53; i++) {
+ if (p_boot->must_be_zero[i]) {
+ pr_info("EXFAT: Attempted to mount VFAT filesystem\n");
+ return -EFSCORRUPTED;
+ }
+ }
+
+ if (p_boot->num_fats != 1 && p_boot->num_fats != 2)
+ return -EFSCORRUPTED;
+
+ /* fill fs_info */
p_fs->sectors_per_clu = 1 << p_boot->sectors_per_clu_shift;
p_fs->sectors_per_clu_bits = p_boot->sectors_per_clu_shift;
p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits +
@@ -2080,11 +2087,9 @@ static s32 read_boot_sector(struct super_block *sb,
p_fs->num_FAT_sectors = le32_to_cpu(p_boot->fat_length);

p_fs->FAT1_start_sector = le32_to_cpu(p_boot->fat_offset);
- if (p_boot->num_fats == 1)
- p_fs->FAT2_start_sector = p_fs->FAT1_start_sector;
- else
- p_fs->FAT2_start_sector = p_fs->FAT1_start_sector +
- p_fs->num_FAT_sectors;
+ p_fs->FAT2_start_sector = p_fs->FAT1_start_sector;
+ if (p_boot->num_fats == 2)
+ p_fs->FAT2_start_sector += p_fs->num_FAT_sectors;

p_fs->root_start_sector = le32_to_cpu(p_boot->clu_offset);
p_fs->data_start_sector = p_fs->root_start_sector;
@@ -2109,71 +2114,50 @@ static s32 read_boot_sector(struct super_block *sb,

s32 exfat_mount(struct super_block *sb)
{
- int i, ret;
- struct boot_sector_t *p_boot;
- struct buffer_head *tmp_bh = NULL;
struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+ int ret;

- /* read Sector 0 */
- if (sector_read(sb, 0, &tmp_bh, 1) != 0) {
- ret = -EIO;
- goto out;
- }
-
- p_boot = (struct boot_sector_t *)tmp_bh->b_data;
-
- /* check the validity of BOOT sector */
- if (le16_to_cpu(p_boot->boot_signature) != BOOT_SIGNATURE) {
- brelse(tmp_bh);
- ret = -EFSCORRUPTED;
- goto out;
- }
-
- /* fill fs_struct */
- for (i = 0; i < 53; i++)
- if (p_boot->must_be_zero[i])
- break;
-
- if (i < 53) {
- /* Not sure how we'd get here, but complain if it does */
- ret = -EINVAL;
- pr_info("EXFAT: Attempted to mount VFAT filesystem\n");
- goto out;
- } else {
- ret = read_boot_sector(sb, p_boot);
- }
+ p_fs->vol_utbl = NULL;
+ p_fs->vol_amap = NULL;

- brelse(tmp_bh);
+ /* read Sector 0 */
+ ret = sector_read(sb, 0, &p_fs->boot_bh, 1);
+ if (ret)
+ goto err_out;

+ ret = read_boot_sector(sb);
if (ret)
- goto out;
+ goto err_out;

ret = load_alloc_bitmap(sb);
if (ret)
- goto out;
+ goto err_out;

ret = load_upcase_table(sb);
- if (ret) {
- free_alloc_bitmap(sb);
- goto out;
- }
+ if (ret)
+ goto err_out;

if (p_fs->dev_ejected) {
- free_upcase_table(sb);
- free_alloc_bitmap(sb);
ret = -EIO;
- goto out;
+ goto err_out;
}

pr_info("[EXFAT] mounted successfully\n");
-out:
+ return 0;
+
+err_out:
+ exfat_umount(sb);
return ret;
}

void exfat_umount(struct super_block *sb)
{
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+
free_upcase_table(sb);
free_alloc_bitmap(sb);
+ brelse(p_fs->boot_bh);
+ p_fs->boot_bh = NULL;
}

s32 create_dir(struct inode *inode, struct chain_t *p_dir,
--
2.25.1