md/raid10: ensure device failure recorded before write request returns.
[pandora-kernel.git] / drivers / md / raid10.c
index 940f2f3..a14c304 100644 (file)
@@ -1681,6 +1681,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
        set_bit(Blocked, &rdev->flags);
        set_bit(Faulty, &rdev->flags);
        set_bit(MD_CHANGE_DEVS, &mddev->flags);
+       set_bit(MD_CHANGE_PENDING, &mddev->flags);
        spin_unlock_irqrestore(&conf->device_lock, flags);
        printk(KERN_ALERT
               "md/raid10:%s: Disk failure on %s, disabling device.\n"
@@ -2738,6 +2739,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
                }
                put_buf(r10_bio);
        } else {
+               bool fail = false;
                for (m = 0; m < conf->copies; m++) {
                        int dev = r10_bio->devs[m].devnum;
                        struct bio *bio = r10_bio->devs[m].bio;
@@ -2750,6 +2752,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
                                rdev_dec_pending(rdev, conf->mddev);
                        } else if (bio != NULL &&
                                   !test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+                               fail = true;
                                if (!narrow_write_error(r10_bio, m)) {
                                        md_error(conf->mddev, rdev);
                                        set_bit(R10BIO_Degraded,
@@ -2770,7 +2773,13 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
                if (test_bit(R10BIO_WriteError,
                             &r10_bio->state))
                        close_write(r10_bio);
-               raid_end_bio_io(r10_bio);
+               if (fail) {
+                       spin_lock_irq(&conf->device_lock);
+                       list_add(&r10_bio->retry_list, &conf->bio_end_io_list);
+                       spin_unlock_irq(&conf->device_lock);
+                       md_wakeup_thread(conf->mddev->thread);
+               } else
+                       raid_end_bio_io(r10_bio);
        }
 }
 
@@ -2785,6 +2794,23 @@ static void raid10d(struct md_thread *thread)
 
        md_check_recovery(mddev);
 
+       if (!list_empty_careful(&conf->bio_end_io_list) &&
+           !test_bit(MD_CHANGE_PENDING, &mddev->flags)) {
+               LIST_HEAD(tmp);
+               spin_lock_irqsave(&conf->device_lock, flags);
+               if (!test_bit(MD_CHANGE_PENDING, &mddev->flags)) {
+                       list_add(&tmp, &conf->bio_end_io_list);
+                       list_del_init(&conf->bio_end_io_list);
+               }
+               spin_unlock_irqrestore(&conf->device_lock, flags);
+               while (!list_empty(&tmp)) {
+                       r10_bio = list_first_entry(&conf->bio_end_io_list,
+                                                 struct r10bio, retry_list);
+                       list_del(&r10_bio->retry_list);
+                       raid_end_bio_io(r10_bio);
+               }
+       }
+
        blk_start_plug(&plug);
        for (;;) {
 
@@ -3556,8 +3582,10 @@ static struct r10conf *setup_conf(struct mddev *mddev)
                        /* far_copies must be 1 */
                        conf->prev.stride = conf->dev_sectors;
        }
+       conf->reshape_safe = conf->reshape_progress;
        spin_lock_init(&conf->device_lock);
        INIT_LIST_HEAD(&conf->retry_list);
+       INIT_LIST_HEAD(&conf->bio_end_io_list);
 
        spin_lock_init(&conf->resync_lock);
        init_waitqueue_head(&conf->wait_barrier);
@@ -3760,7 +3788,6 @@ static int run(struct mddev *mddev)
                }
                conf->offset_diff = min_offset_diff;
 
-               conf->reshape_safe = conf->reshape_progress;
                clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
                clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
                set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
@@ -4103,6 +4130,7 @@ static int raid10_start_reshape(struct mddev *mddev)
                conf->reshape_progress = size;
        } else
                conf->reshape_progress = 0;
+       conf->reshape_safe = conf->reshape_progress;
        spin_unlock_irq(&conf->device_lock);
 
        if (mddev->delta_disks && mddev->bitmap) {
@@ -4170,6 +4198,7 @@ abort:
                rdev->new_data_offset = rdev->data_offset;
        smp_wmb();
        conf->reshape_progress = MaxSector;
+       conf->reshape_safe = MaxSector;
        mddev->reshape_position = MaxSector;
        spin_unlock_irq(&conf->device_lock);
        return ret;
@@ -4213,7 +4242,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
         * at a time, possibly less if that exceeds RESYNC_PAGES,
         * or we hit a bad block or something.
         * This might mean we pause for normal IO in the middle of
-        * a chunk, but that is not a problem was mddev->reshape_position
+        * a chunk, but that is not a problem as mddev->reshape_position
         * can record any location.
         *
         * If we will want to write to a location that isn't
@@ -4237,7 +4266,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
         *
         * In all this the minimum difference in data offsets
         * (conf->offset_diff - always positive) allows a bit of slack,
-        * so next can be after 'safe', but not by more than offset_disk
+        * so next can be after 'safe', but not by more than offset_diff
         *
         * We need to prepare all the bios here before we start any IO
         * to ensure the size we choose is acceptable to all devices.
@@ -4524,6 +4553,7 @@ static void end_reshape(struct r10conf *conf)
        md_finish_reshape(conf->mddev);
        smp_wmb();
        conf->reshape_progress = MaxSector;
+       conf->reshape_safe = MaxSector;
        spin_unlock_irq(&conf->device_lock);
 
        /* read-ahead size must cover two whole stripes, which is