dm delay: add flush as a third class of IO

Add a new class for dm-delay that delays flush requests.  Previously,
flushes were delayed as writes, but it caused problems if the user
needed to create a device with one or a few slow sectors for the purpose
of testing - all flushes would be forwarded to this device and delayed,
and that skews the test results.  Fix this by allowing to select 0 delay
for flushes.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
This commit is contained in:
Mikulas Patocka 2018-04-17 00:33:14 +02:00 committed by Mike Snitzer
parent 3876ac76f0
commit cda6b5ab7f
2 changed files with 32 additions and 5 deletions

View File

@ -5,7 +5,8 @@ Device-Mapper's "delay" target delays reads and/or writes
and maps them to different devices. and maps them to different devices.
Parameters: Parameters:
<device> <offset> <delay> [<write_device> <write_offset> <write_delay>] <device> <offset> <delay> [<write_device> <write_offset> <write_delay>
[<flush_device> <flush_offset> <flush_delay>]]
With separate write parameters, the first set is only used for reads. With separate write parameters, the first set is only used for reads.
Offsets are specified in sectors. Offsets are specified in sectors.

View File

@ -34,6 +34,7 @@ struct delay_c {
struct delay_class read; struct delay_class read;
struct delay_class write; struct delay_class write;
struct delay_class flush;
int argc; int argc;
}; };
@ -126,6 +127,8 @@ static void delay_dtr(struct dm_target *ti)
dm_put_device(ti, dc->read.dev); dm_put_device(ti, dc->read.dev);
if (dc->write.dev) if (dc->write.dev)
dm_put_device(ti, dc->write.dev); dm_put_device(ti, dc->write.dev);
if (dc->flush.dev)
dm_put_device(ti, dc->flush.dev);
mutex_destroy(&dc->timer_lock); mutex_destroy(&dc->timer_lock);
@ -171,8 +174,8 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
struct delay_c *dc; struct delay_c *dc;
int ret; int ret;
if (argc != 3 && argc != 6) { if (argc != 3 && argc != 6 && argc != 9) {
ti->error = "Requires exactly 3 or 6 arguments"; ti->error = "Requires exactly 3, 6 or 9 arguments";
return -EINVAL; return -EINVAL;
} }
@ -196,6 +199,9 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (argc == 3) { if (argc == 3) {
ret = delay_class_ctr(ti, &dc->write, argv); ret = delay_class_ctr(ti, &dc->write, argv);
if (ret)
goto bad;
ret = delay_class_ctr(ti, &dc->flush, argv);
if (ret) if (ret)
goto bad; goto bad;
goto out; goto out;
@ -204,6 +210,16 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ret = delay_class_ctr(ti, &dc->write, argv + 3); ret = delay_class_ctr(ti, &dc->write, argv + 3);
if (ret) if (ret)
goto bad; goto bad;
if (argc == 6) {
ret = delay_class_ctr(ti, &dc->flush, argv + 3);
if (ret)
goto bad;
goto out;
}
ret = delay_class_ctr(ti, &dc->flush, argv + 6);
if (ret)
goto bad;
out: out:
dc->kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0); dc->kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0);
@ -269,7 +285,10 @@ static int delay_map(struct dm_target *ti, struct bio *bio)
struct dm_delay_info *delayed = dm_per_bio_data(bio, sizeof(struct dm_delay_info)); struct dm_delay_info *delayed = dm_per_bio_data(bio, sizeof(struct dm_delay_info));
if (bio_data_dir(bio) == WRITE) { if (bio_data_dir(bio) == WRITE) {
c = &dc->write; if (unlikely(bio->bi_opf & REQ_PREFLUSH))
c = &dc->flush;
else
c = &dc->write;
} else { } else {
c = &dc->read; c = &dc->read;
} }
@ -292,7 +311,7 @@ static void delay_status(struct dm_target *ti, status_type_t type,
switch (type) { switch (type) {
case STATUSTYPE_INFO: case STATUSTYPE_INFO:
DMEMIT("%u %u", dc->read.ops, dc->write.ops); DMEMIT("%u %u %u", dc->read.ops, dc->write.ops, dc->flush.ops);
break; break;
case STATUSTYPE_TABLE: case STATUSTYPE_TABLE:
@ -301,6 +320,10 @@ static void delay_status(struct dm_target *ti, status_type_t type,
DMEMIT(" "); DMEMIT(" ");
DMEMIT_DELAY_CLASS(&dc->write); DMEMIT_DELAY_CLASS(&dc->write);
} }
if (dc->argc >= 9) {
DMEMIT(" ");
DMEMIT_DELAY_CLASS(&dc->flush);
}
break; break;
} }
} }
@ -317,6 +340,9 @@ static int delay_iterate_devices(struct dm_target *ti,
ret = fn(ti, dc->write.dev, dc->write.start, ti->len, data); ret = fn(ti, dc->write.dev, dc->write.start, ti->len, data);
if (ret) if (ret)
goto out; goto out;
ret = fn(ti, dc->flush.dev, dc->flush.start, ti->len, data);
if (ret)
goto out;
out: out:
return ret; return ret;