Use .end_io hook to corrupt_bio_data() after reads complete. Signed-off-by: Mike Snitzer <snitzer@xxxxxxxxxx> --- drivers/md/dm-flakey.c | 40 ++++++++++++++++++++++++++++++++++------ 1 files changed, 34 insertions(+), 6 deletions(-) diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c index b26f61d..54ab455 100644 --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -28,6 +28,7 @@ struct flakey_c { unsigned down_interval; unsigned long flags; unsigned corrupt_bio_byte; + unsigned corrupt_bio_data_dir; }; enum feature_flag_bits { @@ -42,8 +43,9 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc, const char *arg_name; static struct dm_arg _args[] = { - {0, 3, "invalid number of feature args"}, + {0, 4, "invalid number of feature args"}, {1, UINT_MAX, "invalid corrupt bio byte value"}, + {0, 1, "invalid corrupt bio data direction"}, }; r = dm_read_arg(_args, dm_shift_arg(as), &argc, &ti->error); @@ -57,12 +59,20 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc, arg_name = dm_shift_arg(as); argc--; - /* corrupt_bio_byte <Nth byte> */ + /* corrupt_bio_byte <Nth byte> <READ=0|WRITE=1> */ + /* snitm: could also allow user to only corrupt bios that + * have specific bi_rw flag(s), e.g.: (REQ_WRITE|REQ_META)? + */ 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? */ + r = dm_read_arg(_args + 2, dm_shift_arg(as), + &fc->corrupt_bio_data_dir, &ti->error); + argc--; continue; } @@ -204,9 +214,11 @@ static int flakey_map(struct dm_target *ti, struct bio *bio, if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) { unsigned rw = bio_data_dir(bio); if (fc->corrupt_bio_byte) { - /* corrupt writes but don't touch reads */ - if (rw == WRITE) + /* only corrupt either reads or writes */ + if (rw == WRITE && rw == fc->corrupt_bio_data_dir) corrupt_bio_data(bio, fc); + /* flag this bio as submitted while down */ + map_context->ll = 1; goto map_bio; } if (test_bit(DROP_WRITES, &fc->flags)) { @@ -227,6 +239,20 @@ map_bio: return DM_MAPIO_REMAPPED; } +static int flakey_end_io(struct dm_target *ti, struct bio *bio, + int error, union map_info *map_context) +{ + struct flakey_c *fc = ti->private; + unsigned bio_submitted_while_down = map_context->ll; + unsigned rw = bio_data_dir(bio); + + if (!error && bio_submitted_while_down) + if (rw == READ && rw == fc->corrupt_bio_data_dir) + corrupt_bio_data(bio, fc); + + return error; +} + static int flakey_status(struct dm_target *ti, status_type_t type, char *result, unsigned int maxlen) { @@ -246,10 +272,11 @@ static int flakey_status(struct dm_target *ti, status_type_t type, drop_writes = test_bit(DROP_WRITES, &fc->flags); DMEMIT("%u ", drop_writes + - (fc->corrupt_bio_byte > 0) * 2); + (fc->corrupt_bio_byte > 0) * 3); if (fc->corrupt_bio_byte) - DMEMIT("corrupt_bio_byte %u ", fc->corrupt_bio_byte); + DMEMIT("corrupt_bio_byte %u %u ", fc->corrupt_bio_byte, + fc->corrupt_bio_data_dir); if (drop_writes) DMEMIT("drop_writes "); break; @@ -293,6 +320,7 @@ static struct target_type flakey_target = { .ctr = flakey_ctr, .dtr = flakey_dtr, .map = flakey_map, + .end_io = flakey_end_io, .status = flakey_status, .ioctl = flakey_ioctl, .merge = flakey_merge, -- 1.7.1 -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel