]> err.no Git - linux-2.6/commitdiff
dm: unplug queues in threads
authorMikulas Patocka <mpatocka@redhat.com>
Thu, 24 Apr 2008 21:10:47 +0000 (22:10 +0100)
committerAlasdair G Kergon <agk@redhat.com>
Fri, 25 Apr 2008 12:26:57 +0000 (13:26 +0100)
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>
drivers/md/dm-io.c
drivers/md/dm-kcopyd.c
drivers/md/dm-raid1.c

index ed9c86cd053e81f32b5c6551d3246461c00d5d30..4789c42d9a3ac503d53ba6ea77fe7fadbee21682 100644 (file)
@@ -353,7 +353,7 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
 {
        struct io io;
 
-       if (num_regions > 1 && rw != WRITE) {
+       if (num_regions > 1 && (rw & RW_MASK) != WRITE) {
                WARN_ON(1);
                return -EIO;
        }
@@ -390,7 +390,7 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions,
 {
        struct io *io;
 
-       if (num_regions > 1 && rw != WRITE) {
+       if (num_regions > 1 && (rw & RW_MASK) != WRITE) {
                WARN_ON(1);
                fn(1, context);
                return -EIO;
@@ -436,7 +436,12 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp)
 }
 
 /*
- * New collapsed (a)synchronous interface
+ * New collapsed (a)synchronous interface.
+ *
+ * If the IO is asynchronous (i.e. it has notify.fn), you must either unplug
+ * the queue with blk_unplug() some time later or set the BIO_RW_SYNC bit in
+ * io_req->bi_rw. If you fail to do one of these, the IO will be submitted to
+ * the disk after q->unplug_delay, which defaults to 3ms in blk-settings.c.
  */
 int dm_io(struct dm_io_request *io_req, unsigned num_regions,
          struct dm_io_region *where, unsigned long *sync_error_bits)
index ee9583bee04d549cad92a7a809c220d6071f89bd..996802b8a4522e50126365d070f21458f9b68be2 100644 (file)
@@ -332,7 +332,7 @@ static int run_io_job(struct kcopyd_job *job)
 {
        int r;
        struct dm_io_request io_req = {
-               .bi_rw = job->rw,
+               .bi_rw = job->rw | (1 << BIO_RW_SYNC),
                .mem.type = DM_IO_PAGE_LIST,
                .mem.ptr.pl = job->pages,
                .mem.offset = job->offset,
index 3b9532fc294c9952fc80cb31fd028f82e25040f5..ff05fe89308313ab5792a6b3dc9146db3e585c6a 100644 (file)
@@ -1297,6 +1297,8 @@ static void do_mirror(struct work_struct *work)
        do_reads(ms, &reads);
        do_writes(ms, &writes);
        do_failures(ms, &failures);
+
+       dm_table_unplug_all(ms->ti->table);
 }