dm flakey: introduce "error_writes" feature

Recent dm-flakey fixes, to have reads error out during the "down"
interval, made it so that the previous read behaviour is no longer
available.

It is useful to have reads complete like normal but have writes error
out, so make it possible again with a new "error_writes" feature.

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
This commit is contained in:
Mike Snitzer 2016-12-13 14:54:50 -05:00
parent e99dda8fc4
commit ef548c551e

View File

@ -36,7 +36,8 @@ struct flakey_c {
}; };
enum feature_flag_bits { enum feature_flag_bits {
DROP_WRITES DROP_WRITES,
ERROR_WRITES
}; };
struct per_bio_data { struct per_bio_data {
@ -76,6 +77,25 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
if (test_and_set_bit(DROP_WRITES, &fc->flags)) { if (test_and_set_bit(DROP_WRITES, &fc->flags)) {
ti->error = "Feature drop_writes duplicated"; ti->error = "Feature drop_writes duplicated";
return -EINVAL; return -EINVAL;
} else if (test_bit(ERROR_WRITES, &fc->flags)) {
ti->error = "Feature drop_writes conflicts with feature error_writes";
return -EINVAL;
}
continue;
}
/*
* error_writes
*/
if (!strcasecmp(arg_name, "error_writes")) {
if (test_and_set_bit(ERROR_WRITES, &fc->flags)) {
ti->error = "Feature error_writes duplicated";
return -EINVAL;
} else if (test_bit(DROP_WRITES, &fc->flags)) {
ti->error = "Feature error_writes conflicts with feature drop_writes";
return -EINVAL;
} }
continue; continue;
@ -135,6 +155,10 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
if (test_bit(DROP_WRITES, &fc->flags) && (fc->corrupt_bio_rw == WRITE)) { if (test_bit(DROP_WRITES, &fc->flags) && (fc->corrupt_bio_rw == WRITE)) {
ti->error = "drop_writes is incompatible with corrupt_bio_byte with the WRITE flag set"; ti->error = "drop_writes is incompatible with corrupt_bio_byte with the WRITE flag set";
return -EINVAL; return -EINVAL;
} else if (test_bit(ERROR_WRITES, &fc->flags) && (fc->corrupt_bio_rw == WRITE)) {
ti->error = "error_writes is incompatible with corrupt_bio_byte with the WRITE flag set";
return -EINVAL;
} }
return 0; return 0;
@ -291,22 +315,27 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
pb->bio_submitted = true; pb->bio_submitted = true;
/* /*
* Error reads if neither corrupt_bio_byte or drop_writes are set. * Error reads if neither corrupt_bio_byte or drop_writes or error_writes are set.
* Otherwise, flakey_end_io() will decide if the reads should be modified. * Otherwise, flakey_end_io() will decide if the reads should be modified.
*/ */
if (bio_data_dir(bio) == READ) { if (bio_data_dir(bio) == READ) {
if (!fc->corrupt_bio_byte && !test_bit(DROP_WRITES, &fc->flags)) if (!fc->corrupt_bio_byte && !test_bit(DROP_WRITES, &fc->flags) &&
!test_bit(ERROR_WRITES, &fc->flags))
return -EIO; return -EIO;
goto map_bio; goto map_bio;
} }
/* /*
* Drop writes? * Drop or error writes?
*/ */
if (test_bit(DROP_WRITES, &fc->flags)) { if (test_bit(DROP_WRITES, &fc->flags)) {
bio_endio(bio); bio_endio(bio);
return DM_MAPIO_SUBMITTED; return DM_MAPIO_SUBMITTED;
} }
else if (test_bit(ERROR_WRITES, &fc->flags)) {
bio_io_error(bio);
return DM_MAPIO_SUBMITTED;
}
/* /*
* Corrupt matching writes. * Corrupt matching writes.
@ -342,10 +371,11 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio, int error)
*/ */
corrupt_bio_data(bio, fc); corrupt_bio_data(bio, fc);
} else if (!test_bit(DROP_WRITES, &fc->flags)) { } else if (!test_bit(DROP_WRITES, &fc->flags) &&
!test_bit(ERROR_WRITES, &fc->flags)) {
/* /*
* Error read during the down_interval if drop_writes * Error read during the down_interval if drop_writes
* wasn't configured. * and error_writes were not configured.
*/ */
return -EIO; return -EIO;
} }
@ -359,7 +389,7 @@ static void flakey_status(struct dm_target *ti, status_type_t type,
{ {
unsigned sz = 0; unsigned sz = 0;
struct flakey_c *fc = ti->private; struct flakey_c *fc = ti->private;
unsigned drop_writes; unsigned drop_writes, error_writes;
switch (type) { switch (type) {
case STATUSTYPE_INFO: case STATUSTYPE_INFO:
@ -372,10 +402,13 @@ static void flakey_status(struct dm_target *ti, status_type_t type,
fc->down_interval); fc->down_interval);
drop_writes = test_bit(DROP_WRITES, &fc->flags); drop_writes = test_bit(DROP_WRITES, &fc->flags);
DMEMIT("%u ", drop_writes + (fc->corrupt_bio_byte > 0) * 5); error_writes = test_bit(ERROR_WRITES, &fc->flags);
DMEMIT("%u ", drop_writes + error_writes + (fc->corrupt_bio_byte > 0) * 5);
if (drop_writes) if (drop_writes)
DMEMIT("drop_writes "); DMEMIT("drop_writes ");
else if (error_writes)
DMEMIT("error_writes ");
if (fc->corrupt_bio_byte) if (fc->corrupt_bio_byte)
DMEMIT("corrupt_bio_byte %u %c %u %u ", DMEMIT("corrupt_bio_byte %u %c %u %u ",
@ -412,7 +445,7 @@ static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_
static struct target_type flakey_target = { static struct target_type flakey_target = {
.name = "flakey", .name = "flakey",
.version = {1, 3, 1}, .version = {1, 4, 0},
.module = THIS_MODULE, .module = THIS_MODULE,
.ctr = flakey_ctr, .ctr = flakey_ctr,
.dtr = flakey_dtr, .dtr = flakey_dtr,