dm-flakey: make corrupting read bios work
[ Upstream commit 13e79076c89f6e96a6cca8f6df38b40d025907b4 ]
dm-flakey corrupts the read bios in the endio function. However, the
corrupt_bio_* functions checked bio_has_data() to see if there was data
to corrupt. Since this was the endio function, there was no data left to
complete, so bio_has_data() was always false. Fix this by saving a copy
of the bio's bi_iter in flakey_map(), and using this to initialize the
iter for corrupting the read bios. This patch also skips cloning the bio
for write bios with no data.
Reported-by: Kent Overstreet <kent.overstreet@linux.dev>
Fixes: a3998799fb
("dm flakey: add corrupt_bio_byte feature")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
1aef0e1083
commit
8412696035
@@ -47,7 +47,8 @@ enum feature_flag_bits {
|
||||
};
|
||||
|
||||
struct per_bio_data {
|
||||
bool bio_submitted;
|
||||
bool bio_can_corrupt;
|
||||
struct bvec_iter saved_iter;
|
||||
};
|
||||
|
||||
static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
|
||||
@@ -339,7 +340,8 @@ static void flakey_map_bio(struct dm_target *ti, struct bio *bio)
|
||||
}
|
||||
|
||||
static void corrupt_bio_common(struct bio *bio, unsigned int corrupt_bio_byte,
|
||||
unsigned char corrupt_bio_value)
|
||||
unsigned char corrupt_bio_value,
|
||||
struct bvec_iter start)
|
||||
{
|
||||
struct bvec_iter iter;
|
||||
struct bio_vec bvec;
|
||||
@@ -348,7 +350,7 @@ static void corrupt_bio_common(struct bio *bio, unsigned int corrupt_bio_byte,
|
||||
* Overwrite the Nth byte of the bio's data, on whichever page
|
||||
* it falls.
|
||||
*/
|
||||
bio_for_each_segment(bvec, bio, iter) {
|
||||
__bio_for_each_segment(bvec, bio, iter, start) {
|
||||
if (bio_iter_len(bio, iter) > corrupt_bio_byte) {
|
||||
unsigned char *segment = bvec_kmap_local(&bvec);
|
||||
segment[corrupt_bio_byte] = corrupt_bio_value;
|
||||
@@ -357,36 +359,31 @@ static void corrupt_bio_common(struct bio *bio, unsigned int corrupt_bio_byte,
|
||||
"(rw=%c bi_opf=%u bi_sector=%llu size=%u)\n",
|
||||
bio, corrupt_bio_value, corrupt_bio_byte,
|
||||
(bio_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_opf,
|
||||
(unsigned long long)bio->bi_iter.bi_sector,
|
||||
bio->bi_iter.bi_size);
|
||||
(unsigned long long)start.bi_sector,
|
||||
start.bi_size);
|
||||
break;
|
||||
}
|
||||
corrupt_bio_byte -= bio_iter_len(bio, iter);
|
||||
}
|
||||
}
|
||||
|
||||
static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
|
||||
static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc,
|
||||
struct bvec_iter start)
|
||||
{
|
||||
unsigned int corrupt_bio_byte = fc->corrupt_bio_byte - 1;
|
||||
|
||||
if (!bio_has_data(bio))
|
||||
return;
|
||||
|
||||
corrupt_bio_common(bio, corrupt_bio_byte, fc->corrupt_bio_value);
|
||||
corrupt_bio_common(bio, corrupt_bio_byte, fc->corrupt_bio_value, start);
|
||||
}
|
||||
|
||||
static void corrupt_bio_random(struct bio *bio)
|
||||
static void corrupt_bio_random(struct bio *bio, struct bvec_iter start)
|
||||
{
|
||||
unsigned int corrupt_byte;
|
||||
unsigned char corrupt_value;
|
||||
|
||||
if (!bio_has_data(bio))
|
||||
return;
|
||||
|
||||
corrupt_byte = get_random_u32() % bio->bi_iter.bi_size;
|
||||
corrupt_byte = get_random_u32() % start.bi_size;
|
||||
corrupt_value = get_random_u8();
|
||||
|
||||
corrupt_bio_common(bio, corrupt_byte, corrupt_value);
|
||||
corrupt_bio_common(bio, corrupt_byte, corrupt_value, start);
|
||||
}
|
||||
|
||||
static void clone_free(struct bio *clone)
|
||||
@@ -481,7 +478,7 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
|
||||
unsigned int elapsed;
|
||||
struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
|
||||
|
||||
pb->bio_submitted = false;
|
||||
pb->bio_can_corrupt = false;
|
||||
|
||||
if (op_is_zone_mgmt(bio_op(bio)))
|
||||
goto map_bio;
|
||||
@@ -490,10 +487,11 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
|
||||
elapsed = (jiffies - fc->start_time) / HZ;
|
||||
if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) {
|
||||
bool corrupt_fixed, corrupt_random;
|
||||
/*
|
||||
* Flag this bio as submitted while down.
|
||||
*/
|
||||
pb->bio_submitted = true;
|
||||
|
||||
if (bio_has_data(bio)) {
|
||||
pb->bio_can_corrupt = true;
|
||||
pb->saved_iter = bio->bi_iter;
|
||||
}
|
||||
|
||||
/*
|
||||
* Error reads if neither corrupt_bio_byte or drop_writes or error_writes are set.
|
||||
@@ -516,6 +514,8 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
}
|
||||
|
||||
if (!pb->bio_can_corrupt)
|
||||
goto map_bio;
|
||||
/*
|
||||
* Corrupt matching writes.
|
||||
*/
|
||||
@@ -535,9 +535,11 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
|
||||
struct bio *clone = clone_bio(ti, fc, bio);
|
||||
if (clone) {
|
||||
if (corrupt_fixed)
|
||||
corrupt_bio_data(clone, fc);
|
||||
corrupt_bio_data(clone, fc,
|
||||
clone->bi_iter);
|
||||
if (corrupt_random)
|
||||
corrupt_bio_random(clone);
|
||||
corrupt_bio_random(clone,
|
||||
clone->bi_iter);
|
||||
submit_bio(clone);
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
}
|
||||
@@ -559,21 +561,21 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio,
|
||||
if (op_is_zone_mgmt(bio_op(bio)))
|
||||
return DM_ENDIO_DONE;
|
||||
|
||||
if (!*error && pb->bio_submitted && (bio_data_dir(bio) == READ)) {
|
||||
if (!*error && pb->bio_can_corrupt && (bio_data_dir(bio) == READ)) {
|
||||
if (fc->corrupt_bio_byte) {
|
||||
if ((fc->corrupt_bio_rw == READ) &&
|
||||
all_corrupt_bio_flags_match(bio, fc)) {
|
||||
/*
|
||||
* Corrupt successful matching READs while in down state.
|
||||
*/
|
||||
corrupt_bio_data(bio, fc);
|
||||
corrupt_bio_data(bio, fc, pb->saved_iter);
|
||||
}
|
||||
}
|
||||
if (fc->random_read_corrupt) {
|
||||
u64 rnd = get_random_u64();
|
||||
u32 rem = do_div(rnd, PROBABILITY_BASE);
|
||||
if (rem < fc->random_read_corrupt)
|
||||
corrupt_bio_random(bio);
|
||||
corrupt_bio_random(bio, pb->saved_iter);
|
||||
}
|
||||
if (test_bit(ERROR_READS, &fc->flags)) {
|
||||
/*
|
||||
|
Reference in New Issue
Block a user