diff options
author | Mikulas Patocka <mpatocka@redhat.com> | 2018-04-17 00:33:14 +0200 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2018-07-27 15:24:19 -0400 |
commit | cda6b5ab7f5935565ed5b9bbc385bd1d0a3feb75 (patch) | |
tree | f9874d8e3e6d0f6dbefcba98c6835f37694f6009 | |
parent | 3876ac76f02ac2a7b3d96f813c0ee1070e7a8c8e (diff) | |
download | lwn-cda6b5ab7f5935565ed5b9bbc385bd1d0a3feb75.tar.gz lwn-cda6b5ab7f5935565ed5b9bbc385bd1d0a3feb75.zip |
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>
-rw-r--r-- | Documentation/device-mapper/delay.txt | 3 | ||||
-rw-r--r-- | drivers/md/dm-delay.c | 34 |
2 files changed, 32 insertions, 5 deletions
diff --git a/Documentation/device-mapper/delay.txt b/Documentation/device-mapper/delay.txt index 4b1d22a44ce4..6426c45273cb 100644 --- a/Documentation/device-mapper/delay.txt +++ b/Documentation/device-mapper/delay.txt @@ -5,7 +5,8 @@ Device-Mapper's "delay" target delays reads and/or writes and maps them to different devices. 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. Offsets are specified in sectors. diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c index c5ebe56bc28b..2fb7bb4304ad 100644 --- a/drivers/md/dm-delay.c +++ b/drivers/md/dm-delay.c @@ -34,6 +34,7 @@ struct delay_c { struct delay_class read; struct delay_class write; + struct delay_class flush; int argc; }; @@ -126,6 +127,8 @@ static void delay_dtr(struct dm_target *ti) dm_put_device(ti, dc->read.dev); if (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); @@ -171,8 +174,8 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv) struct delay_c *dc; int ret; - if (argc != 3 && argc != 6) { - ti->error = "Requires exactly 3 or 6 arguments"; + if (argc != 3 && argc != 6 && argc != 9) { + ti->error = "Requires exactly 3, 6 or 9 arguments"; return -EINVAL; } @@ -198,12 +201,25 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv) ret = delay_class_ctr(ti, &dc->write, argv); if (ret) goto bad; + ret = delay_class_ctr(ti, &dc->flush, argv); + if (ret) + goto bad; goto out; } ret = delay_class_ctr(ti, &dc->write, argv + 3); if (ret) 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: 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)); if (bio_data_dir(bio) == WRITE) { - c = &dc->write; + if (unlikely(bio->bi_opf & REQ_PREFLUSH)) + c = &dc->flush; + else + c = &dc->write; } else { c = &dc->read; } @@ -292,7 +311,7 @@ static void delay_status(struct dm_target *ti, status_type_t type, switch (type) { 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; case STATUSTYPE_TABLE: @@ -301,6 +320,10 @@ static void delay_status(struct dm_target *ti, status_type_t type, DMEMIT(" "); DMEMIT_DELAY_CLASS(&dc->write); } + if (dc->argc >= 9) { + DMEMIT(" "); + DMEMIT_DELAY_CLASS(&dc->flush); + } 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); if (ret) goto out; + ret = fn(ti, dc->flush.dev, dc->flush.start, ti->len, data); + if (ret) + goto out; out: return ret; |