Skip to content

Commit cb09122

Browse files
adam900710kdave
authored andcommitted
btrfs: fix remaining u32 overflows when left shifting stripe_nr
There was regression caused by a97699d ("btrfs: replace map_lookup->stripe_len by BTRFS_STRIPE_LEN") and supposedly fixed by a7299a1 ("btrfs: fix u32 overflows when left shifting stripe_nr"). To avoid code churn the fix was open coding the type casts but unfortunately missed one which was still possible to hit [1]. The missing place was assignment of bioc->full_stripe_logical inside btrfs_map_block(). Fix it by adding a helper that does the safe calculation of the offset and use it everywhere even though it may not be strictly necessary due to already using u64 types. This replaces all remaining "<< BTRFS_STRIPE_LEN_SHIFT" calls. [1] https://lore.kernel.org/linux-btrfs/20230622065438.86402-1-wqu@suse.com/ Fixes: a7299a1 ("btrfs: fix u32 overflows when left shifting stripe_nr") Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> [ update changelog ] Signed-off-by: David Sterba <dsterba@suse.com>
1 parent a7299a1 commit cb09122

File tree

5 files changed

+40
-28
lines changed

5 files changed

+40
-28
lines changed

fs/btrfs/block-group.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1973,7 +1973,7 @@ int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 chunk_start,
19731973

19741974
/* For RAID5/6 adjust to a full IO stripe length */
19751975
if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
1976-
io_stripe_size = nr_data_stripes(map) << BTRFS_STRIPE_LEN_SHIFT;
1976+
io_stripe_size = btrfs_stripe_nr_to_offset(nr_data_stripes(map));
19771977

19781978
buf = kcalloc(map->num_stripes, sizeof(u64), GFP_NOFS);
19791979
if (!buf) {

fs/btrfs/scrub.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,7 +1304,7 @@ static int get_raid56_logic_offset(u64 physical, int num,
13041304
u32 stripe_index;
13051305
u32 rot;
13061306

1307-
*offset = last_offset + (i << BTRFS_STRIPE_LEN_SHIFT);
1307+
*offset = last_offset + btrfs_stripe_nr_to_offset(i);
13081308

13091309
stripe_nr = (u32)(*offset >> BTRFS_STRIPE_LEN_SHIFT) / data_stripes;
13101310

@@ -1319,7 +1319,7 @@ static int get_raid56_logic_offset(u64 physical, int num,
13191319
if (stripe_index < num)
13201320
j++;
13211321
}
1322-
*offset = last_offset + (j << BTRFS_STRIPE_LEN_SHIFT);
1322+
*offset = last_offset + btrfs_stripe_nr_to_offset(j);
13231323
return 1;
13241324
}
13251325

@@ -1715,7 +1715,7 @@ static int flush_scrub_stripes(struct scrub_ctx *sctx)
17151715
ASSERT(test_bit(SCRUB_STRIPE_FLAG_INITIALIZED, &sctx->stripes[0].state));
17161716

17171717
scrub_throttle_dev_io(sctx, sctx->stripes[0].dev,
1718-
nr_stripes << BTRFS_STRIPE_LEN_SHIFT);
1718+
btrfs_stripe_nr_to_offset(nr_stripes));
17191719
for (int i = 0; i < nr_stripes; i++) {
17201720
stripe = &sctx->stripes[i];
17211721
scrub_submit_initial_read(sctx, stripe);
@@ -1838,7 +1838,7 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
18381838
bool all_empty = true;
18391839
const int data_stripes = nr_data_stripes(map);
18401840
unsigned long extent_bitmap = 0;
1841-
u64 length = data_stripes << BTRFS_STRIPE_LEN_SHIFT;
1841+
u64 length = btrfs_stripe_nr_to_offset(data_stripes);
18421842
int ret;
18431843

18441844
ASSERT(sctx->raid56_data_stripes);
@@ -1853,13 +1853,13 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
18531853
data_stripes) >> BTRFS_STRIPE_LEN_SHIFT;
18541854
stripe_index = (i + rot) % map->num_stripes;
18551855
physical = map->stripes[stripe_index].physical +
1856-
(rot << BTRFS_STRIPE_LEN_SHIFT);
1856+
btrfs_stripe_nr_to_offset(rot);
18571857

18581858
scrub_reset_stripe(stripe);
18591859
set_bit(SCRUB_STRIPE_FLAG_NO_REPORT, &stripe->state);
18601860
ret = scrub_find_fill_first_stripe(bg,
18611861
map->stripes[stripe_index].dev, physical, 1,
1862-
full_stripe_start + (i << BTRFS_STRIPE_LEN_SHIFT),
1862+
full_stripe_start + btrfs_stripe_nr_to_offset(i),
18631863
BTRFS_STRIPE_LEN, stripe);
18641864
if (ret < 0)
18651865
goto out;
@@ -1869,7 +1869,7 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
18691869
*/
18701870
if (ret > 0) {
18711871
stripe->logical = full_stripe_start +
1872-
(i << BTRFS_STRIPE_LEN_SHIFT);
1872+
btrfs_stripe_nr_to_offset(i);
18731873
stripe->dev = map->stripes[stripe_index].dev;
18741874
stripe->mirror_num = 1;
18751875
set_bit(SCRUB_STRIPE_FLAG_INITIALIZED, &stripe->state);
@@ -2062,7 +2062,7 @@ static u64 simple_stripe_full_stripe_len(const struct map_lookup *map)
20622062
ASSERT(map->type & (BTRFS_BLOCK_GROUP_RAID0 |
20632063
BTRFS_BLOCK_GROUP_RAID10));
20642064

2065-
return (map->num_stripes / map->sub_stripes) << BTRFS_STRIPE_LEN_SHIFT;
2065+
return btrfs_stripe_nr_to_offset(map->num_stripes / map->sub_stripes);
20662066
}
20672067

20682068
/* Get the logical bytenr for the stripe */
@@ -2078,7 +2078,7 @@ static u64 simple_stripe_get_logical(struct map_lookup *map,
20782078
* (stripe_index / sub_stripes) gives how many data stripes we need to
20792079
* skip.
20802080
*/
2081-
return ((stripe_index / map->sub_stripes) << BTRFS_STRIPE_LEN_SHIFT) +
2081+
return btrfs_stripe_nr_to_offset(stripe_index / map->sub_stripes) +
20822082
bg->start;
20832083
}
20842084

@@ -2204,7 +2204,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
22042204
}
22052205
if (profile & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) {
22062206
ret = scrub_simple_stripe(sctx, bg, map, scrub_dev, stripe_index);
2207-
offset = (stripe_index / map->sub_stripes) << BTRFS_STRIPE_LEN_SHIFT;
2207+
offset = btrfs_stripe_nr_to_offset(stripe_index / map->sub_stripes);
22082208
goto out;
22092209
}
22102210

@@ -2219,7 +2219,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
22192219

22202220
/* Initialize @offset in case we need to go to out: label */
22212221
get_raid56_logic_offset(physical, stripe_index, map, &offset, NULL);
2222-
increment = nr_data_stripes(map) << BTRFS_STRIPE_LEN_SHIFT;
2222+
increment = btrfs_stripe_nr_to_offset(nr_data_stripes(map));
22232223

22242224
/*
22252225
* Due to the rotation, for RAID56 it's better to iterate each stripe

fs/btrfs/tree-checker.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -857,10 +857,10 @@ int btrfs_check_chunk_valid(struct extent_buffer *leaf,
857857
*
858858
* Thus it should be a good way to catch obvious bitflips.
859859
*/
860-
if (unlikely(length >= ((u64)U32_MAX << BTRFS_STRIPE_LEN_SHIFT))) {
860+
if (unlikely(length >= btrfs_stripe_nr_to_offset(U32_MAX))) {
861861
chunk_err(leaf, chunk, logical,
862862
"chunk length too large: have %llu limit %llu",
863-
length, (u64)U32_MAX << BTRFS_STRIPE_LEN_SHIFT);
863+
length, btrfs_stripe_nr_to_offset(U32_MAX));
864864
return -EUCLEAN;
865865
}
866866
if (unlikely(type & ~(BTRFS_BLOCK_GROUP_TYPE_MASK |

fs/btrfs/volumes.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5125,7 +5125,7 @@ static void init_alloc_chunk_ctl_policy_regular(
51255125
/* We don't want a chunk larger than 10% of writable space */
51265126
ctl->max_chunk_size = min(mult_perc(fs_devices->total_rw_bytes, 10),
51275127
ctl->max_chunk_size);
5128-
ctl->dev_extent_min = ctl->dev_stripes << BTRFS_STRIPE_LEN_SHIFT;
5128+
ctl->dev_extent_min = btrfs_stripe_nr_to_offset(ctl->dev_stripes);
51295129
}
51305130

51315131
static void init_alloc_chunk_ctl_policy_zoned(
@@ -5801,7 +5801,7 @@ unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info,
58015801
if (!WARN_ON(IS_ERR(em))) {
58025802
map = em->map_lookup;
58035803
if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
5804-
len = nr_data_stripes(map) << BTRFS_STRIPE_LEN_SHIFT;
5804+
len = btrfs_stripe_nr_to_offset(nr_data_stripes(map));
58055805
free_extent_map(em);
58065806
}
58075807
return len;
@@ -5975,12 +5975,12 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
59755975
stripe_nr = offset >> BTRFS_STRIPE_LEN_SHIFT;
59765976

59775977
/* stripe_offset is the offset of this block in its stripe */
5978-
stripe_offset = offset - ((u64)stripe_nr << BTRFS_STRIPE_LEN_SHIFT);
5978+
stripe_offset = offset - btrfs_stripe_nr_to_offset(stripe_nr);
59795979

59805980
stripe_nr_end = round_up(offset + length, BTRFS_STRIPE_LEN) >>
59815981
BTRFS_STRIPE_LEN_SHIFT;
59825982
stripe_cnt = stripe_nr_end - stripe_nr;
5983-
stripe_end_offset = ((u64)stripe_nr_end << BTRFS_STRIPE_LEN_SHIFT) -
5983+
stripe_end_offset = btrfs_stripe_nr_to_offset(stripe_nr_end) -
59845984
(offset + length);
59855985
/*
59865986
* after this, stripe_nr is the number of stripes on this
@@ -6023,12 +6023,12 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
60236023
for (i = 0; i < *num_stripes; i++) {
60246024
stripes[i].physical =
60256025
map->stripes[stripe_index].physical +
6026-
stripe_offset + ((u64)stripe_nr << BTRFS_STRIPE_LEN_SHIFT);
6026+
stripe_offset + btrfs_stripe_nr_to_offset(stripe_nr);
60276027
stripes[i].dev = map->stripes[stripe_index].dev;
60286028

60296029
if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
60306030
BTRFS_BLOCK_GROUP_RAID10)) {
6031-
stripes[i].length = stripes_per_dev << BTRFS_STRIPE_LEN_SHIFT;
6031+
stripes[i].length = btrfs_stripe_nr_to_offset(stripes_per_dev);
60326032

60336033
if (i / sub_stripes < remaining_stripes)
60346034
stripes[i].length += BTRFS_STRIPE_LEN;
@@ -6183,8 +6183,8 @@ static u64 btrfs_max_io_len(struct map_lookup *map, enum btrfs_map_op op,
61836183
ASSERT(*stripe_offset < U32_MAX);
61846184

61856185
if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
6186-
unsigned long full_stripe_len = nr_data_stripes(map) <<
6187-
BTRFS_STRIPE_LEN_SHIFT;
6186+
unsigned long full_stripe_len =
6187+
btrfs_stripe_nr_to_offset(nr_data_stripes(map));
61886188

61896189
/*
61906190
* For full stripe start, we use previously calculated
@@ -6196,8 +6196,8 @@ static u64 btrfs_max_io_len(struct map_lookup *map, enum btrfs_map_op op,
61966196
* not ensured to be power of 2.
61976197
*/
61986198
*full_stripe_start =
6199-
(u64)rounddown(*stripe_nr, nr_data_stripes(map)) <<
6200-
BTRFS_STRIPE_LEN_SHIFT;
6199+
btrfs_stripe_nr_to_offset(
6200+
rounddown(*stripe_nr, nr_data_stripes(map)));
62016201

62026202
ASSERT(*full_stripe_start + full_stripe_len > offset);
62036203
ASSERT(*full_stripe_start <= offset);
@@ -6223,7 +6223,7 @@ static void set_io_stripe(struct btrfs_io_stripe *dst, const struct map_lookup *
62236223
{
62246224
dst->dev = map->stripes[stripe_index].dev;
62256225
dst->physical = map->stripes[stripe_index].physical +
6226-
stripe_offset + ((u64)stripe_nr << BTRFS_STRIPE_LEN_SHIFT);
6226+
stripe_offset + btrfs_stripe_nr_to_offset(stripe_nr);
62276227
}
62286228

62296229
int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
@@ -6345,7 +6345,8 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
63456345
/* Return the length to the full stripe end */
63466346
*length = min(logical + *length,
63476347
raid56_full_stripe_start + em->start +
6348-
(data_stripes << BTRFS_STRIPE_LEN_SHIFT)) - logical;
6348+
btrfs_stripe_nr_to_offset(data_stripes)) -
6349+
logical;
63496350
stripe_index = 0;
63506351
stripe_offset = 0;
63516352
} else {
@@ -6435,7 +6436,7 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
64356436
* modulo, to reduce one modulo call.
64366437
*/
64376438
bioc->full_stripe_logical = em->start +
6438-
((stripe_nr * data_stripes) << BTRFS_STRIPE_LEN_SHIFT);
6439+
btrfs_stripe_nr_to_offset(stripe_nr * data_stripes);
64396440
for (i = 0; i < num_stripes; i++)
64406441
set_io_stripe(&bioc->stripes[i], map,
64416442
(i + stripe_nr) % num_stripes,
@@ -8032,7 +8033,7 @@ static void map_raid56_repair_block(struct btrfs_io_context *bioc,
80328033

80338034
for (i = 0; i < data_stripes; i++) {
80348035
u64 stripe_start = bioc->full_stripe_logical +
8035-
(i << BTRFS_STRIPE_LEN_SHIFT);
8036+
btrfs_stripe_nr_to_offset(i);
80368037

80378038
if (logical >= stripe_start &&
80388039
logical < stripe_start + BTRFS_STRIPE_LEN)

fs/btrfs/volumes.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,17 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)
574574
sizeof(struct btrfs_stripe) * (num_stripes - 1);
575575
}
576576

577+
/*
578+
* Do the type safe converstion from stripe_nr to offset inside the chunk.
579+
*
580+
* @stripe_nr is u32, with left shift it can overflow u32 for chunks larger
581+
* than 4G. This does the proper type cast to avoid overflow.
582+
*/
583+
static inline u64 btrfs_stripe_nr_to_offset(u32 stripe_nr)
584+
{
585+
return (u64)stripe_nr << BTRFS_STRIPE_LEN_SHIFT;
586+
}
587+
577588
void btrfs_get_bioc(struct btrfs_io_context *bioc);
578589
void btrfs_put_bioc(struct btrfs_io_context *bioc);
579590
int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,

0 commit comments

Comments
 (0)