This patch implements async writes in raid1.
Signed-Off-By: Paul Clements <[EMAIL PROTECTED]>

 drivers/md/raid1.c         |  107 ++++++++++++++++++++++++++++++++++++++++++---
 include/linux/raid/raid1.h |    2 
 2 files changed, 102 insertions(+), 7 deletions(-)
diff -purN --exclude core --exclude-from /export/public/clemep/tmp/dontdiff 
linux-2.6.11-rc3-mm2-patch-all-write-mostly-max-dev-bug-bitmap-bug-fix/drivers/md/raid1.c
 
linux-2.6.11-rc3-mm2-patch-all-write-mostly-async-write-bitmap-bug-fix/drivers/md/raid1.c
--- 
linux-2.6.11-rc3-mm2-patch-all-write-mostly-max-dev-bug-bitmap-bug-fix/drivers/md/raid1.c
   Thu Mar 10 10:05:35 2005
+++ 
linux-2.6.11-rc3-mm2-patch-all-write-mostly-async-write-bitmap-bug-fix/drivers/md/raid1.c
   Sat Mar 12 08:38:20 2005
@@ -35,7 +35,7 @@
 #include <linux/raid/raid1.h>
 #include <linux/raid/bitmap.h>
 
-#define DEBUG 0
+#define DEBUG 0
 #if DEBUG
 #define PRINTK(x...) printk(x)
 #else
@@ -222,8 +222,17 @@ static void raid_end_bio_io(r1bio_t *r1_
 {
        struct bio *bio = r1_bio->master_bio;
 
-       bio_endio(bio, bio->bi_size,
-               test_bit(R1BIO_Uptodate, &r1_bio->state) ? 0 : -EIO);
+       /* if nobody has done the final endio yet, do it now */
+       if (!test_and_set_bit(R1BIO_AsyncPhase, &r1_bio->state)) {
+               PRINTK(KERN_DEBUG "raid1: sync end %s on sectors %llu-%llu\n",
+                       (bio_data_dir(bio) == WRITE) ? "write" : "read",
+                       (unsigned long long) bio->bi_sector,
+                       (unsigned long long) bio->bi_sector +
+                               (bio->bi_size >> 9) - 1);
+       
+               bio_endio(bio, bio->bi_size,
+                       test_bit(R1BIO_Uptodate, &r1_bio->state) ? 0 : -EIO);
+       }
        free_r1bio(r1_bio);
 }
 
@@ -292,7 +301,7 @@ static int raid1_end_write_request(struc
 {
        int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
-       int mirror;
+       int mirror, async, wonly = 1; /* assume write only if rdev missing */
        conf_t *conf = mddev_to_conf(r1_bio->mddev);
 
        if (bio->bi_size)
@@ -323,16 +332,39 @@ static int raid1_end_write_request(struc
 
        update_head_pos(mirror, r1_bio);
 
+       async = test_bit(R1BIO_AsyncIO, &r1_bio->state);
+       if (conf->mirrors[mirror].rdev)
+               wonly = test_bit(WriteMostly, 
&conf->mirrors[mirror].rdev->flags);
+       /* In async mode, we ACK the master bio once the I/O has safely
+        * reached the non-writeonly disk. Setting the AsyncPhase bit
+        * ensures that this gets done only once -- we don't ever want to
+        * return -EIO here, instead we'll wait */
+       if (async && !wonly && test_bit(R1BIO_Uptodate, &r1_bio->state) &&
+           !test_and_set_bit(R1BIO_AsyncPhase, &r1_bio->state)) {
+               struct bio *mbio = r1_bio->master_bio;
+               PRINTK(KERN_DEBUG "raid1: async end write sectors %llu-%llu\n",
+                       (unsigned long long) mbio->bi_sector,
+                       (unsigned long long) mbio->bi_sector +
+                       (mbio->bi_size >> 9) - 1);
+               bio_endio(mbio, mbio->bi_size, 0);
+       }
        /*
         *
         * Let's see if all mirrored write operations have finished
         * already.
         */
        if (atomic_dec_and_test(&r1_bio->remaining)) {
+               if (async) {
+                       int i = bio->bi_vcnt;
+                       /* free extra copy of the data pages */
+                       while (i--)
+                               __free_page(bio->bi_io_vec[i].bv_page);
+               }
                /* clear the bitmap if all writes complete successfully */
                bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector,
                                r1_bio->sectors,
-                               !test_bit(R1BIO_Degraded, &r1_bio->state));
+                               !test_bit(R1BIO_Degraded, &r1_bio->state),
+                               async);
                md_write_end(r1_bio->mddev);
                raid_end_bio_io(r1_bio);
        }
@@ -553,6 +585,38 @@ static void device_barrier(conf_t *conf,
        spin_unlock_irq(&conf->resync_lock);
 }
 
+/* duplicate the data pages for async I/O */
+static struct page **alloc_async_pages(struct bio *bio)
+{
+       int i;
+       struct bio_vec *bvec;
+       struct page **pages = kmalloc(bio->bi_vcnt * sizeof(struct page *),
+                                       GFP_NOIO);
+       if (unlikely(!pages))
+               goto do_sync_io;
+
+       BUG_ON(bio->bi_idx != 0);
+       bio_for_each_segment(bvec, bio, i) {
+               pages[i] = alloc_page(GFP_NOIO);
+               if (unlikely(!pages[i]))
+                       goto do_sync_io;
+               memcpy(kmap(pages[i]) + bvec->bv_offset,
+                       kmap(bvec->bv_page) + bvec->bv_offset, bvec->bv_len);
+               kunmap(pages[i]);
+               kunmap(bvec->bv_page);
+       }
+
+       return pages;
+
+do_sync_io:
+       if (pages)
+               for (i = 0; i < bio->bi_vcnt && pages[i]; i++)
+                       __free_page(pages[i]);
+       kfree(pages);
+       PRINTK("%dB async alloc failed, doing sync I/O\n", bio->bi_size);
+       return NULL;
+}
+
 static int make_request(request_queue_t *q, struct bio * bio)
 {
        mddev_t *mddev = q->queuedata;
@@ -565,6 +629,7 @@ static int make_request(request_queue_t 
        struct bitmap *bitmap = mddev->bitmap;
        unsigned long flags;
        struct bio_list bl;
+       struct page **async_pages = NULL;
 
 
        /*
@@ -668,6 +733,12 @@ static int make_request(request_queue_t 
                set_bit(R1BIO_Degraded, &r1_bio->state);
        }
 
+       /* do async I/O ? */
+       if (bitmap &&
+           atomic_read(&bitmap->async_writes) < bitmap->async_max_writes &&
+           (async_pages = alloc_async_pages(bio)))
+               set_bit(R1BIO_AsyncIO, &r1_bio->state);
+
        atomic_set(&r1_bio->remaining, 0);
 
        bio_list_init(&bl);
@@ -685,19 +756,30 @@ static int make_request(request_queue_t 
                mbio->bi_rw = WRITE;
                mbio->bi_private = r1_bio;
 
+               if (test_bit(R1BIO_AsyncIO, &r1_bio->state)) {
+                       struct bio_vec *bvec;
+                       int j;
+
+                       BUG_ON(!async_pages);
+                       bio_for_each_segment(bvec, mbio, j)
+                               bvec->bv_page = async_pages[j];
+               }
+
                atomic_inc(&r1_bio->remaining);
 
                bio_list_add(&bl, mbio);
        }
+       kfree(async_pages); /* the async pages are attached to the bios now */
 
-       bitmap_startwrite(bitmap, bio->bi_sector, r1_bio->sectors);
+       bitmap_startwrite(bitmap, bio->bi_sector, r1_bio->sectors,
+                               test_bit(R1BIO_AsyncIO, &r1_bio->state));
        spin_lock_irqsave(&conf->device_lock, flags);
        bio_list_merge(&conf->pending_bio_list, &bl);
        bio_list_init(&bl);
 
        blk_plug_device(mddev->queue);
        spin_unlock_irqrestore(&conf->device_lock, flags);
-       
+
 #if 0
        while ((bio = bio_list_pop(&bl)) != NULL) 
                generic_make_request(bio);
@@ -1458,6 +1540,17 @@ out:
 static int stop(mddev_t *mddev)
 {
        conf_t *conf = mddev_to_conf(mddev);
+       struct bitmap *bitmap = mddev->bitmap;
+       int async_wait = 0;
+
+       /* wait for async writes to complete */
+       while (bitmap && atomic_read(&bitmap->async_writes) > 0) {
+               async_wait++;
+               printk(KERN_INFO "raid1: async writes in progress on device %s, 
waiting to stop (%d)\n", mdname(mddev), async_wait);
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(HZ); /* wait a second */
+               /* need to kick something here to make sure I/O goes? */
+       }
 
        md_unregister_thread(mddev->thread);
        mddev->thread = NULL;
diff -purN --exclude core --exclude-from /export/public/clemep/tmp/dontdiff 
linux-2.6.11-rc3-mm2-patch-all-write-mostly-max-dev-bug-bitmap-bug-fix/include/linux/raid/raid1.h
 
linux-2.6.11-rc3-mm2-patch-all-write-mostly-async-write-bitmap-bug-fix/include/linux/raid/raid1.h
--- 
linux-2.6.11-rc3-mm2-patch-all-write-mostly-max-dev-bug-bitmap-bug-fix/include/linux/raid/raid1.h
   Fri Feb 18 14:45:25 2005
+++ 
linux-2.6.11-rc3-mm2-patch-all-write-mostly-async-write-bitmap-bug-fix/include/linux/raid/raid1.h
   Mon Feb 21 16:48:38 2005
@@ -107,4 +107,6 @@ struct r1bio_s {
 #define        R1BIO_Uptodate  0
 #define        R1BIO_IsSync    1
 #define        R1BIO_Degraded  2
+#define R1BIO_AsyncPhase 3
+#define R1BIO_AsyncIO   4
 #endif

Reply via email to