mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 15:22:21 -04:00
dm dust: make badblock messages target-relative
dm-dust currently treats addbadblock, removebadblock and queryblock arguments as block numbers on the underlying device. That is surprising for a device-mapper target: a dm-dust table with a non-zero backing offset can add bad blocks that are outside the mapped target, and a badblock added for logical block 0 is missed because the I/O path checks the remapped backing-device block instead. Interpret badblock message arguments as blocks relative to the start of the dm-dust target instead. Bound the arguments by the target length and perform badblock lookup using target-relative sectors before remapping the bio to the underlying device. This intentionally changes the non-zero backing-offset behavior to make the badblock control interface match the mapped dm-dust device, rather than the underlying device. Assisted-by: Codex:gpt-5.5-cyber-preview Signed-off-by: Samuel Moelius <sam.moelius@trailofbits.com> Tested-by: Bryan Gurney <bgurney@redhat.com> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
This commit is contained in:
committed by
Mikulas Patocka
parent
cc87e26d9c
commit
066976b7db
@@ -196,7 +196,6 @@ static int __dust_map_write(struct dust_device *dd, sector_t thisblock)
|
||||
dd->badblock_count--;
|
||||
kfree(bblk);
|
||||
if (!dd->quiet_mode) {
|
||||
sector_div(thisblock, dd->sect_per_block);
|
||||
DMINFO("block %llu removed from badblocklist by write",
|
||||
(unsigned long long)thisblock);
|
||||
}
|
||||
@@ -224,15 +223,16 @@ static int dust_map_write(struct dust_device *dd, sector_t thisblock,
|
||||
static int dust_map(struct dm_target *ti, struct bio *bio)
|
||||
{
|
||||
struct dust_device *dd = ti->private;
|
||||
sector_t dust_sector = dm_target_offset(ti, bio->bi_iter.bi_sector);
|
||||
int r;
|
||||
|
||||
bio_set_dev(bio, dd->dev->bdev);
|
||||
bio->bi_iter.bi_sector = dd->start + dm_target_offset(ti, bio->bi_iter.bi_sector);
|
||||
bio->bi_iter.bi_sector = dd->start + dust_sector;
|
||||
|
||||
if (bio_data_dir(bio) == READ)
|
||||
r = dust_map_read(dd, bio->bi_iter.bi_sector, dd->fail_read_on_bb);
|
||||
r = dust_map_read(dd, dust_sector, dd->fail_read_on_bb);
|
||||
else
|
||||
r = dust_map_write(dd, bio->bi_iter.bi_sector, dd->fail_read_on_bb);
|
||||
r = dust_map_write(dd, dust_sector, dd->fail_read_on_bb);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -415,7 +415,7 @@ static int dust_message(struct dm_target *ti, unsigned int argc, char **argv,
|
||||
char *result, unsigned int maxlen)
|
||||
{
|
||||
struct dust_device *dd = ti->private;
|
||||
sector_t size = bdev_nr_sectors(dd->dev->bdev);
|
||||
sector_t size = dm_sector_div_up(ti->len, dd->sect_per_block);
|
||||
bool invalid_msg = false;
|
||||
int r = -EINVAL;
|
||||
unsigned long long tmp, block;
|
||||
@@ -462,8 +462,7 @@ static int dust_message(struct dm_target *ti, unsigned int argc, char **argv,
|
||||
return r;
|
||||
|
||||
block = tmp;
|
||||
sector_div(size, dd->sect_per_block);
|
||||
if (block > size) {
|
||||
if (block >= size) {
|
||||
DMERR("selected block value out of range");
|
||||
return r;
|
||||
}
|
||||
@@ -490,8 +489,7 @@ static int dust_message(struct dm_target *ti, unsigned int argc, char **argv,
|
||||
return r;
|
||||
}
|
||||
wr_fail_cnt = tmp_ui;
|
||||
sector_div(size, dd->sect_per_block);
|
||||
if (block > size) {
|
||||
if (block >= size) {
|
||||
DMERR("selected block value out of range");
|
||||
return r;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user