Commit cda6b5ab authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Mike Snitzer

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: default avatarMikulas Patocka <mpatocka@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent 3876ac76
...@@ -5,7 +5,8 @@ Device-Mapper's "delay" target delays reads and/or writes ...@@ -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.
......
...@@ -34,6 +34,7 @@ struct delay_c { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment