btrfs: don't use btrfs_chunk::sub_stripes from disk
[BUG] There are two reports (the earliest one from LKP, a more recent one from kernel bugzilla) that we can have some chunks with 0 as sub_stripes. This will cause divide-by-zero errors at btrfs_rmap_block, which is introduced by a recent kernel patchac0677348f
("btrfs: merge calculations for simple striped profiles in btrfs_rmap_block"): if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) { stripe_nr = stripe_nr * map->num_stripes + i; stripe_nr = div_u64(stripe_nr, map->sub_stripes); <<< } [CAUSE] From the more recent report, it has been proven that we have some chunks with 0 as sub_stripes, mostly caused by older mkfs. It turns out that the mkfs.btrfs fix is only introduced in 6718ab4d33aa ("btrfs-progs: Initialize sub_stripes to 1 in btrfs_alloc_data_chunk") which is included in v5.4 btrfs-progs release. So there would be quite some old filesystems with such 0 sub_stripes. [FIX] Just don't trust the sub_stripes values from disk. We have a trusted btrfs_raid_array[] to fetch the correct sub_stripes numbers for each profile and that are fixed. By this, we can keep the compatibility with older filesystems while still avoid divide-by-zero bugs. Reported-by: kernel test robot <oliver.sang@intel.com> Reported-by: Viktor Kuzmin <kvaster@gmail.com> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=216559 Fixes:ac0677348f
("btrfs: merge calculations for simple striped profiles in btrfs_rmap_block") CC: stable@vger.kernel.org # 6.0 Reviewed-by: Su Yue <glass@fydeos.io> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Родитель
2398091f9c
Коммит
76a66ba101
|
@ -7142,6 +7142,7 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
|
|||
u64 devid;
|
||||
u64 type;
|
||||
u8 uuid[BTRFS_UUID_SIZE];
|
||||
int index;
|
||||
int num_stripes;
|
||||
int ret;
|
||||
int i;
|
||||
|
@ -7149,6 +7150,7 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
|
|||
logical = key->offset;
|
||||
length = btrfs_chunk_length(leaf, chunk);
|
||||
type = btrfs_chunk_type(leaf, chunk);
|
||||
index = btrfs_bg_flags_to_raid_index(type);
|
||||
num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
|
||||
|
||||
#if BITS_PER_LONG == 32
|
||||
|
@ -7202,7 +7204,15 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
|
|||
map->io_align = btrfs_chunk_io_align(leaf, chunk);
|
||||
map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
|
||||
map->type = type;
|
||||
map->sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk);
|
||||
/*
|
||||
* We can't use the sub_stripes value, as for profiles other than
|
||||
* RAID10, they may have 0 as sub_stripes for filesystems created by
|
||||
* older mkfs (<v5.4).
|
||||
* In that case, it can cause divide-by-zero errors later.
|
||||
* Since currently sub_stripes is fixed for each profile, let's
|
||||
* use the trusted value instead.
|
||||
*/
|
||||
map->sub_stripes = btrfs_raid_array[index].sub_stripes;
|
||||
map->verified_stripes = 0;
|
||||
em->orig_block_len = btrfs_calc_stripe_length(em);
|
||||
for (i = 0; i < num_stripes; i++) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче