aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2008-04-24 17:10:47 -0400
committerAlasdair G Kergon <agk@redhat.com>2008-04-25 08:26:57 -0400
commit7ff14a36159d947872870e7a3e9dcaebc46b23eb (patch)
tree69544b7f29f2ffc392951f9e9c23f566e3cc41f7 /drivers/md
parenta2aebe03be60ae4da03507a00d60211d5e0327c3 (diff)
dm: unplug queues in threads
Remove an avoidable 3ms delay on some dm-raid1 and kcopyd I/O. It is specified that any submitted bio without BIO_RW_SYNC flag may plug the queue (i.e. block the requests from being dispatched to the physical device). The queue is unplugged when the caller calls blk_unplug() function. Usually, the sequence is that someone calls submit_bh to submit IO on a buffer. The IO plugs the queue and waits (to be possibly joined with other adjacent bios). Then, when the caller calls wait_on_buffer(), it unplugs the queue and submits the IOs to the disk. This was happenning: When doing O_SYNC writes, function fsync_buffers_list() submits a list of bios to dm_raid1, the bios are added to dm_raid1 write queue and kmirrord is woken up. fsync_buffers_list() calls wait_on_buffer(). That unplugs the queue, but there are no bios on the device queue as they are still in the dm_raid1 queue. wait_on_buffer() starts waiting until the IO is finished. kmirrord is scheduled, kmirrord takes bios and submits them to the devices. The submitted bio plugs the harddisk queue but there is no one to unplug it. (The process that called wait_on_buffer() is already sleeping.) So there is a 3ms timeout, after which the queues on the harddisks are unplugged and requests are processed. This 3ms timeout meant that in certain workloads (e.g. O_SYNC, 8kb writes), dm-raid1 is 10 times slower than md raid1. Every time we submit something asynchronously via dm_io, we must unplug the queue actually to send the request to the device. This patch adds an unplug call to kmirrord - while processing requests, it keeps the queue plugged (so that adjacent bios can be merged); when it finishes processing all the bios, it unplugs the queue to submit the bios. It also fixes kcopyd which has the same potential problem. All kcopyd requests are submitted with BIO_RW_SYNC. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com> Acked-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/dm-io.c11
-rw-r--r--drivers/md/dm-kcopyd.c2
-rw-r--r--drivers/md/dm-raid1.c2
3 files changed, 11 insertions, 4 deletions
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index ed9c86cd053e..4789c42d9a3a 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -353,7 +353,7 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
353{ 353{
354 struct io io; 354 struct io io;
355 355
356 if (num_regions > 1 && rw != WRITE) { 356 if (num_regions > 1 && (rw & RW_MASK) != WRITE) {
357 WARN_ON(1); 357 WARN_ON(1);
358 return -EIO; 358 return -EIO;
359 } 359 }
@@ -390,7 +390,7 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions,
390{ 390{
391 struct io *io; 391 struct io *io;
392 392
393 if (num_regions > 1 && rw != WRITE) { 393 if (num_regions > 1 && (rw & RW_MASK) != WRITE) {
394 WARN_ON(1); 394 WARN_ON(1);
395 fn(1, context); 395 fn(1, context);
396 return -EIO; 396 return -EIO;
@@ -436,7 +436,12 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp)
436} 436}
437 437
438/* 438/*
439 * New collapsed (a)synchronous interface 439 * New collapsed (a)synchronous interface.
440 *
441 * If the IO is asynchronous (i.e. it has notify.fn), you must either unplug
442 * the queue with blk_unplug() some time later or set the BIO_RW_SYNC bit in
443 * io_req->bi_rw. If you fail to do one of these, the IO will be submitted to
444 * the disk after q->unplug_delay, which defaults to 3ms in blk-settings.c.
440 */ 445 */
441int dm_io(struct dm_io_request *io_req, unsigned num_regions, 446int dm_io(struct dm_io_request *io_req, unsigned num_regions,
442 struct dm_io_region *where, unsigned long *sync_error_bits) 447 struct dm_io_region *where, unsigned long *sync_error_bits)
diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c
index ee9583bee04d..996802b8a452 100644
--- a/drivers/md/dm-kcopyd.c
+++ b/drivers/md/dm-kcopyd.c
@@ -332,7 +332,7 @@ static int run_io_job(struct kcopyd_job *job)
332{ 332{
333 int r; 333 int r;
334 struct dm_io_request io_req = { 334 struct dm_io_request io_req = {
335 .bi_rw = job->rw, 335 .bi_rw = job->rw | (1 << BIO_RW_SYNC),
336 .mem.type = DM_IO_PAGE_LIST, 336 .mem.type = DM_IO_PAGE_LIST,
337 .mem.ptr.pl = job->pages, 337 .mem.ptr.pl = job->pages,
338 .mem.offset = job->offset, 338 .mem.offset = job->offset,
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 3b9532fc294c..ff05fe893083 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -1297,6 +1297,8 @@ static void do_mirror(struct work_struct *work)
1297 do_reads(ms, &reads); 1297 do_reads(ms, &reads);
1298 do_writes(ms, &writes); 1298 do_writes(ms, &writes);
1299 do_failures(ms, &failures); 1299 do_failures(ms, &failures);
1300
1301 dm_table_unplug_all(ms->ti->table);
1300} 1302}
1301 1303
1302 1304