Pull bugzilla-5452 into release branch
[pandora-kernel.git] / drivers / md / raid10.c
index 9e658e5..1440935 100644 (file)
@@ -176,7 +176,7 @@ static void put_all_bios(conf_t *conf, r10bio_t *r10_bio)
        }
 }
 
-static inline void free_r10bio(r10bio_t *r10_bio)
+static void free_r10bio(r10bio_t *r10_bio)
 {
        conf_t *conf = mddev_to_conf(r10_bio->mddev);
 
@@ -190,7 +190,7 @@ static inline void free_r10bio(r10bio_t *r10_bio)
        mempool_free(r10_bio, conf->r10bio_pool);
 }
 
-static inline void put_buf(r10bio_t *r10_bio)
+static void put_buf(r10bio_t *r10_bio)
 {
        conf_t *conf = mddev_to_conf(r10_bio->mddev);
 
@@ -565,6 +565,8 @@ rb_out:
 
        if (disk >= 0 && (rdev=rcu_dereference(conf->mirrors[disk].rdev))!= NULL)
                atomic_inc(&conf->mirrors[disk].rdev->nr_pending);
+       else
+               disk = -1;
        rcu_read_unlock();
 
        return disk;
@@ -1115,8 +1117,7 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
        for (i=0; i<conf->copies; i++)
                if (r10_bio->devs[i].bio == bio)
                        break;
-       if (i == conf->copies)
-               BUG();
+       BUG_ON(i == conf->copies);
        update_head_pos(i, r10_bio);
        d = r10_bio->devs[i].devnum;
 
@@ -1406,43 +1407,54 @@ static void raid10d(mddev_t *mddev)
                                if (s > (PAGE_SIZE>>9))
                                        s = PAGE_SIZE >> 9;
 
+                               rcu_read_lock();
                                do {
                                        int d = r10_bio->devs[sl].devnum;
-                                       rdev = conf->mirrors[d].rdev;
+                                       rdev = rcu_dereference(conf->mirrors[d].rdev);
                                        if (rdev &&
-                                           test_bit(In_sync, &rdev->flags) &&
-                                           sync_page_io(rdev->bdev,
-                                                        r10_bio->devs[sl].addr +
-                                                        sect + rdev->data_offset,
-                                                        s<<9,
-                                                        conf->tmppage, READ))
-                                               success = 1;
-                                       else {
-                                               sl++;
-                                               if (sl == conf->copies)
-                                                       sl = 0;
+                                           test_bit(In_sync, &rdev->flags)) {
+                                               atomic_inc(&rdev->nr_pending);
+                                               rcu_read_unlock();
+                                               success = sync_page_io(rdev->bdev,
+                                                                      r10_bio->devs[sl].addr +
+                                                                      sect + rdev->data_offset,
+                                                                      s<<9,
+                                                                      conf->tmppage, READ);
+                                               rdev_dec_pending(rdev, mddev);
+                                               rcu_read_lock();
+                                               if (success)
+                                                       break;
                                        }
+                                       sl++;
+                                       if (sl == conf->copies)
+                                               sl = 0;
                                } while (!success && sl != r10_bio->read_slot);
+                               rcu_read_unlock();
 
                                if (success) {
                                        int start = sl;
                                        /* write it back and re-read */
+                                       rcu_read_lock();
                                        while (sl != r10_bio->read_slot) {
                                                int d;
                                                if (sl==0)
                                                        sl = conf->copies;
                                                sl--;
                                                d = r10_bio->devs[sl].devnum;
-                                               rdev = conf->mirrors[d].rdev;
-                                               atomic_add(s, &rdev->corrected_errors);
+                                               rdev = rcu_dereference(conf->mirrors[d].rdev);
                                                if (rdev &&
                                                    test_bit(In_sync, &rdev->flags)) {
+                                                       atomic_inc(&rdev->nr_pending);
+                                                       rcu_read_unlock();
+                                                       atomic_add(s, &rdev->corrected_errors);
                                                        if (sync_page_io(rdev->bdev,
                                                                         r10_bio->devs[sl].addr +
                                                                         sect + rdev->data_offset,
                                                                         s<<9, conf->tmppage, WRITE) == 0)
                                                                /* Well, this device is dead */
                                                                md_error(mddev, rdev);
+                                                       rdev_dec_pending(rdev, mddev);
+                                                       rcu_read_lock();
                                                }
                                        }
                                        sl = start;
@@ -1452,17 +1464,22 @@ static void raid10d(mddev_t *mddev)
                                                        sl = conf->copies;
                                                sl--;
                                                d = r10_bio->devs[sl].devnum;
-                                               rdev = conf->mirrors[d].rdev;
+                                               rdev = rcu_dereference(conf->mirrors[d].rdev);
                                                if (rdev &&
                                                    test_bit(In_sync, &rdev->flags)) {
+                                                       atomic_inc(&rdev->nr_pending);
+                                                       rcu_read_unlock();
                                                        if (sync_page_io(rdev->bdev,
                                                                         r10_bio->devs[sl].addr +
                                                                         sect + rdev->data_offset,
                                                                         s<<9, conf->tmppage, READ) == 0)
                                                                /* Well, this device is dead */
                                                                md_error(mddev, rdev);
+                                                       rdev_dec_pending(rdev, mddev);
+                                                       rcu_read_lock();
                                                }
                                        }
+                                       rcu_read_unlock();
                                } else {
                                        /* Cannot read from anywhere -- bye bye array */
                                        md_error(mddev, conf->mirrors[r10_bio->devs[r10_bio->read_slot].devnum].rdev);
@@ -1516,8 +1533,7 @@ static int init_resync(conf_t *conf)
        int buffs;
 
        buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE;
-       if (conf->r10buf_pool)
-               BUG();
+       BUG_ON(conf->r10buf_pool);
        conf->r10buf_pool = mempool_create(buffs, r10buf_pool_alloc, r10buf_pool_free, conf);
        if (!conf->r10buf_pool)
                return -ENOMEM;