From: Mike Snitzer User may specify a series of bio->bi_rw flags that must be seen in order to trigger corruption (e.g. 33 = REQ_WRITE|REQ_META). Signed-off-by: Mike Snitzer --- drivers/md/dm-flakey.c | 35 ++++++++++++++++++++++------------- drivers/md/dm-flakey.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) Index: linux/drivers/md/dm-flakey.c =================================================================== --- linux.orig/drivers/md/dm-flakey.c +++ linux/drivers/md/dm-flakey.c @@ -28,7 +28,7 @@ struct flakey_c { unsigned down_interval; unsigned long flags; unsigned corrupt_bio_byte; - unsigned corrupt_bio_data_dir; + unsigned corrupt_bio_flags; }; enum feature_flag_bits { @@ -45,7 +45,7 @@ static int parse_features(struct dm_arg_ static struct dm_arg _args[] = { {0, 4, "invalid number of feature args"}, {1, UINT_MAX, "invalid corrupt bio byte value"}, - {0, 1, "invalid corrupt bio data direction"}, + {0, UINT_MAX, "invalid corrupt bio flags mask"}, }; /* No feature arguments supplied. */ @@ -60,19 +60,19 @@ static int parse_features(struct dm_arg_ arg_name = dm_shift_arg(as); argc--; - /* corrupt_bio_byte */ - /* snitm: could also allow user to only corrupt bios that - * have specific bi_rw flag(s), e.g.: (REQ_WRITE|REQ_META)? - */ + /* corrupt_bio_byte */ if (!strnicmp(arg_name, MESG_STR("corrupt_bio_byte")) && (argc >= 1)) { r = dm_read_arg(_args + 1, dm_shift_arg(as), &fc->corrupt_bio_byte, &ti->error); argc--; - /* corrupt reads or writes? */ + /* + * Only corrupt bios that have specific bi_rw flag(s), + * e.g.: READ=0 or REQ_WRITE=1|REQ_META=32 + */ r = dm_read_arg(_args + 2, dm_shift_arg(as), - &fc->corrupt_bio_data_dir, &ti->error); + &fc->corrupt_bio_flags, &ti->error); argc--; continue; } @@ -190,14 +190,20 @@ static void flakey_map_bio(struct dm_tar bio->bi_sector = flakey_map_sector(ti, bio->bi_sector); } +#define corrupt_bio_data_dir(fc) ((fc)->corrupt_bio_flags & 1) +#define all_corrupt_bio_flags_match(fc, bio) \ + (((bio)->bi_rw & (fc)->corrupt_bio_flags) == (fc)->corrupt_bio_flags) + static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc) { unsigned bio_bytes = bio_cur_bytes(bio); char *data = bio_data(bio); /* write 0 to the specified Nth byte of the bio */ - if (data && bio_bytes >= fc->corrupt_bio_byte) + if (data && bio_bytes >= fc->corrupt_bio_byte) { data[fc->corrupt_bio_byte-1] = 0; + printk("corrupting data rw=%lu\n", bio_data_dir(bio)); + } } static int flakey_map(struct dm_target *ti, struct bio *bio, @@ -211,9 +217,11 @@ static int flakey_map(struct dm_target * if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) { unsigned rw = bio_data_dir(bio); if (fc->corrupt_bio_byte) { - /* only corrupt either reads or writes */ - if (rw == WRITE && rw == fc->corrupt_bio_data_dir) + /* corrupt matching writes, defer reads until end_io */ + if (rw == WRITE && rw == corrupt_bio_data_dir(fc) && + all_corrupt_bio_flags_match(fc, bio)) corrupt_bio_data(bio, fc); + /* flag this bio as submitted while down */ map_context->ll = 1; goto map_bio; @@ -244,7 +252,8 @@ static int flakey_end_io(struct dm_targe unsigned rw = bio_data_dir(bio); if (!error && bio_submitted_while_down) - if (rw == READ && rw == fc->corrupt_bio_data_dir) + if (rw == READ && rw == corrupt_bio_data_dir(fc) && + all_corrupt_bio_flags_match(fc, bio)) corrupt_bio_data(bio, fc); return error; @@ -273,7 +282,7 @@ static int flakey_status(struct dm_targe if (fc->corrupt_bio_byte) DMEMIT("corrupt_bio_byte %u %u ", fc->corrupt_bio_byte, - fc->corrupt_bio_data_dir); + fc->corrupt_bio_flags); if (drop_writes) DMEMIT("drop_writes "); break;