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:
parent
3876ac76f0
commit
cda6b5ab7f
|
@ -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 {
|
||||||
|
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue