mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 06:02:05 +00:00
Description for this pull request:
- Improve file deletion performance with dirsync mount option. - fix shift-out-of-bounds in exfat_fill_super() generated by syzkaller. -----BEGIN PGP SIGNATURE----- iQJMBAABCgA2FiEE6NzKS6Uv/XAAGHgyZwv7A1FEIQgFAmAzA7MYHG5hbWphZS5q ZW9uQHNhbXN1bmcuY29tAAoJEGcL+wNRRCEIYKMP/1i4uV1KebeQTkIiNlPMae+H hq2TgkrOLp7gKY+G8VoSrYIG9U5fEGh+bo6UwIXQpGDrnFb9AWAE0YoyCUV0sTGS 6CQmmjl1Cq4gwmBs2yjkbmGa54d2NRExZc2zMewDxnWRQjIvqJftxh1qowjwN13j arfjvWGJ61Je/S1jQ0vS0+nC5f4Mcy+60JyAQB4gxX5327o1ZVohs16jYTTZuS4+ PsARwM+q3wYQ/THeTf01E/a77IfsS49EtR1aTo8/9fCfQCxKdYT0wkJQQ/J0yhTL l6LMp1PNHV3iePRPZWAF15n8eB2dXGfcaathgtecY+9arKJVDnAoALt91gxN1bxE ZZZWkOlviN4FmdQvKNtVaBhdAxNqybe1P0yLvH1Vm2nY0oyY+qgQ79A/xNWcBvhg Q6Y1fV08KLWRPsafoZVntb3pd/DT1ekeedrFuqPe3c6kTziFn1GmUhb+6DGCEoFs 2sbuxATOJCdNL4GHLt0CRNQYU2Dm6g0yuQ3qodu4wcco9yUgiNXe2sM6NpMXaTH7 XUlgsaxl8zO5TKrVfre93gIP48HRf2/gZu8ejXs2rUEIzhSy3rsIMyt2DhTUe9Db CW2SMGQADG9Aiod4gRaunvMrTE3S7NMXLsOG5K6eThar8fOnqQ/F0NHi5DUWuFdw 17G5gwimXbZxW0GhTvWH =kzJV -----END PGP SIGNATURE----- Merge tag 'exfat-for-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat Pull exfat updates from Namjae Jeon: - improve file deletion performance with dirsync mount option - fix shift-out-of-bounds in exfat_fill_super() reported by syzkaller * tag 'exfat-for-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat: exfat: improve performance of exfat_free_cluster when using dirsync mount option exfat: fix shift-out-of-bounds in exfat_fill_super()
This commit is contained in:
commit
c63dca9e23
@ -166,7 +166,7 @@ int exfat_set_bitmap(struct inode *inode, unsigned int clu)
|
||||
* If the value of "clu" is 0, it means cluster 2 which is the first cluster of
|
||||
* the cluster heap.
|
||||
*/
|
||||
void exfat_clear_bitmap(struct inode *inode, unsigned int clu)
|
||||
void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync)
|
||||
{
|
||||
int i, b;
|
||||
unsigned int ent_idx;
|
||||
@ -180,7 +180,7 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu)
|
||||
b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
|
||||
|
||||
clear_bit_le(b, sbi->vol_amap[i]->b_data);
|
||||
exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode));
|
||||
exfat_update_bh(sbi->vol_amap[i], sync);
|
||||
|
||||
if (opts->discard) {
|
||||
int ret_discard;
|
||||
|
@ -408,7 +408,7 @@ int exfat_count_num_clusters(struct super_block *sb,
|
||||
int exfat_load_bitmap(struct super_block *sb);
|
||||
void exfat_free_bitmap(struct exfat_sb_info *sbi);
|
||||
int exfat_set_bitmap(struct inode *inode, unsigned int clu);
|
||||
void exfat_clear_bitmap(struct inode *inode, unsigned int clu);
|
||||
void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync);
|
||||
unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu);
|
||||
int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count);
|
||||
|
||||
|
@ -77,6 +77,10 @@
|
||||
|
||||
#define EXFAT_FILE_NAME_LEN 15
|
||||
|
||||
#define EXFAT_MIN_SECT_SIZE_BITS 9
|
||||
#define EXFAT_MAX_SECT_SIZE_BITS 12
|
||||
#define EXFAT_MAX_SECT_PER_CLUS_BITS(x) (25 - (x)->sect_size_bits)
|
||||
|
||||
/* EXFAT: Main and Backup Boot Sector (512 bytes) */
|
||||
struct boot_sector {
|
||||
__u8 jmp_boot[BOOTSEC_JUMP_BOOT_LEN];
|
||||
|
@ -157,6 +157,7 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
|
||||
unsigned int clu;
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct exfat_sb_info *sbi = EXFAT_SB(sb);
|
||||
int cur_cmap_i, next_cmap_i;
|
||||
|
||||
/* invalid cluster number */
|
||||
if (p_chain->dir == EXFAT_FREE_CLUSTER ||
|
||||
@ -176,21 +177,51 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
|
||||
|
||||
clu = p_chain->dir;
|
||||
|
||||
if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
|
||||
do {
|
||||
exfat_clear_bitmap(inode, clu);
|
||||
clu++;
|
||||
cur_cmap_i = next_cmap_i =
|
||||
BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(clu));
|
||||
|
||||
if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
|
||||
unsigned int last_cluster = p_chain->dir + p_chain->size - 1;
|
||||
do {
|
||||
bool sync = false;
|
||||
|
||||
if (clu < last_cluster)
|
||||
next_cmap_i =
|
||||
BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(clu+1));
|
||||
|
||||
/* flush bitmap only if index would be changed or for last cluster */
|
||||
if (clu == last_cluster || cur_cmap_i != next_cmap_i) {
|
||||
sync = true;
|
||||
cur_cmap_i = next_cmap_i;
|
||||
}
|
||||
|
||||
exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode)));
|
||||
clu++;
|
||||
num_clusters++;
|
||||
} while (num_clusters < p_chain->size);
|
||||
} else {
|
||||
do {
|
||||
exfat_clear_bitmap(inode, clu);
|
||||
bool sync = false;
|
||||
unsigned int n_clu = clu;
|
||||
int err = exfat_get_next_cluster(sb, &n_clu);
|
||||
|
||||
if (exfat_get_next_cluster(sb, &clu))
|
||||
goto dec_used_clus;
|
||||
if (err || n_clu == EXFAT_EOF_CLUSTER)
|
||||
sync = true;
|
||||
else
|
||||
next_cmap_i =
|
||||
BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(n_clu));
|
||||
|
||||
if (cur_cmap_i != next_cmap_i) {
|
||||
sync = true;
|
||||
cur_cmap_i = next_cmap_i;
|
||||
}
|
||||
|
||||
exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode)));
|
||||
clu = n_clu;
|
||||
num_clusters++;
|
||||
|
||||
if (err)
|
||||
goto dec_used_clus;
|
||||
} while (clu != EXFAT_EOF_CLUSTER);
|
||||
}
|
||||
|
||||
|
@ -381,8 +381,7 @@ static int exfat_calibrate_blocksize(struct super_block *sb, int logical_sect)
|
||||
{
|
||||
struct exfat_sb_info *sbi = EXFAT_SB(sb);
|
||||
|
||||
if (!is_power_of_2(logical_sect) ||
|
||||
logical_sect < 512 || logical_sect > 4096) {
|
||||
if (!is_power_of_2(logical_sect)) {
|
||||
exfat_err(sb, "bogus logical sector size %u", logical_sect);
|
||||
return -EIO;
|
||||
}
|
||||
@ -451,6 +450,25 @@ static int exfat_read_boot_sector(struct super_block *sb)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* sect_size_bits could be at least 9 and at most 12.
|
||||
*/
|
||||
if (p_boot->sect_size_bits < EXFAT_MIN_SECT_SIZE_BITS ||
|
||||
p_boot->sect_size_bits > EXFAT_MAX_SECT_SIZE_BITS) {
|
||||
exfat_err(sb, "bogus sector size bits : %u\n",
|
||||
p_boot->sect_size_bits);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* sect_per_clus_bits could be at least 0 and at most 25 - sect_size_bits.
|
||||
*/
|
||||
if (p_boot->sect_per_clus_bits > EXFAT_MAX_SECT_PER_CLUS_BITS(p_boot)) {
|
||||
exfat_err(sb, "bogus sectors bits per cluster : %u\n",
|
||||
p_boot->sect_per_clus_bits);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sbi->sect_per_clus = 1 << p_boot->sect_per_clus_bits;
|
||||
sbi->sect_per_clus_bits = p_boot->sect_per_clus_bits;
|
||||
sbi->cluster_size_bits = p_boot->sect_per_clus_bits +
|
||||
@ -477,16 +495,19 @@ static int exfat_read_boot_sector(struct super_block *sb)
|
||||
sbi->used_clusters = EXFAT_CLUSTERS_UNTRACKED;
|
||||
|
||||
/* check consistencies */
|
||||
if (sbi->num_FAT_sectors << p_boot->sect_size_bits <
|
||||
sbi->num_clusters * 4) {
|
||||
if ((u64)sbi->num_FAT_sectors << p_boot->sect_size_bits <
|
||||
(u64)sbi->num_clusters * 4) {
|
||||
exfat_err(sb, "bogus fat length");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sbi->data_start_sector <
|
||||
sbi->FAT1_start_sector + sbi->num_FAT_sectors * p_boot->num_fats) {
|
||||
(u64)sbi->FAT1_start_sector +
|
||||
(u64)sbi->num_FAT_sectors * p_boot->num_fats) {
|
||||
exfat_err(sb, "bogus data start sector");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sbi->vol_flags & VOLUME_DIRTY)
|
||||
exfat_warn(sb, "Volume was not properly unmounted. Some data may be corrupt. Please run fsck.");
|
||||
if (sbi->vol_flags & MEDIA_FAILURE)
|
||||
|
Loading…
Reference in New Issue
Block a user