ehea: Whitespace cleanup
[safe/jmp/linux-2.6] / drivers / md / raid10.c
index 8f58a44..9eb66c1 100644 (file)
@@ -29,6 +29,7 @@
  *    raid_disks
  *    near_copies (stored in low byte of layout)
  *    far_copies (stored in second byte of layout)
+ *    far_offset (stored in bit 16 of layout )
  *
  * The data to be stored is divided into chunks using chunksize.
  * Each device is divided into far_copies sections.
  * near_copies copies of each chunk is stored (each on a different drive).
  * The starting device for each section is offset near_copies from the starting
  * device of the previous section.
- * Thus there are (near_copies*far_copies) of each chunk, and each is on a different
+ * Thus they are (near_copies*far_copies) of each chunk, and each is on a different
  * drive.
  * near_copies and far_copies must be at least one, and their product is at most
  * raid_disks.
+ *
+ * If far_offset is true, then the far_copies are handled a bit differently.
+ * The copies are still in different stripes, but instead of be very far apart
+ * on disk, there are adjacent stripes.
  */
 
 /*
@@ -59,10 +64,8 @@ static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
        int size = offsetof(struct r10bio_s, devs[conf->copies]);
 
        /* allocate a r10bio with room for raid_disks entries in the bios array */
-       r10_bio = kmalloc(size, gfp_flags);
-       if (r10_bio)
-               memset(r10_bio, 0, size);
-       else
+       r10_bio = kzalloc(size, gfp_flags);
+       if (!r10_bio)
                unplug_slaves(conf->mddev);
 
        return r10_bio;
@@ -134,10 +137,10 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
 
 out_free_pages:
        for ( ; i > 0 ; i--)
-               __free_page(bio->bi_io_vec[i-1].bv_page);
+               safe_put_page(bio->bi_io_vec[i-1].bv_page);
        while (j--)
                for (i = 0; i < RESYNC_PAGES ; i++)
-                       __free_page(r10_bio->devs[j].bio->bi_io_vec[i].bv_page);
+                       safe_put_page(r10_bio->devs[j].bio->bi_io_vec[i].bv_page);
        j = -1;
 out_free_bio:
        while ( ++j < nalloc )
@@ -157,7 +160,7 @@ static void r10buf_pool_free(void *__r10_bio, void *data)
                struct bio *bio = r10bio->devs[j].bio;
                if (bio) {
                        for (i = 0; i < RESYNC_PAGES; i++) {
-                               __free_page(bio->bi_io_vec[i].bv_page);
+                               safe_put_page(bio->bi_io_vec[i].bv_page);
                                bio->bi_io_vec[i].bv_page = NULL;
                        }
                        bio_put(bio);
@@ -172,13 +175,13 @@ static void put_all_bios(conf_t *conf, r10bio_t *r10_bio)
 
        for (i = 0; i < conf->copies; i++) {
                struct bio **bio = & r10_bio->devs[i].bio;
-               if (*bio)
+               if (*bio && *bio != IO_BLOCKED)
                        bio_put(*bio);
                *bio = NULL;
        }
 }
 
-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);
 
@@ -192,7 +195,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);
 
@@ -209,6 +212,7 @@ static void reschedule_retry(r10bio_t *r10_bio)
 
        spin_lock_irqsave(&conf->device_lock, flags);
        list_add(&r10_bio->retry_list, &conf->retry_list);
+       conf->nr_queued ++;
        spin_unlock_irqrestore(&conf->device_lock, flags);
 
        md_wakeup_thread(mddev->thread);
@@ -254,9 +258,9 @@ static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int
        /*
         * this branch is our 'one mirror IO has finished' event handler:
         */
-       if (!uptodate)
-               md_error(r10_bio->mddev, conf->mirrors[dev].rdev);
-       else
+       update_head_pos(slot, r10_bio);
+
+       if (uptodate) {
                /*
                 * Set R10BIO_Uptodate in our master bio, so that
                 * we will return a good error code to the higher
@@ -267,15 +271,8 @@ static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int
                 * wait for the 'master' bio.
                 */
                set_bit(R10BIO_Uptodate, &r10_bio->state);
-
-       update_head_pos(slot, r10_bio);
-
-       /*
-        * we have only one bio on the read side
-        */
-       if (uptodate)
                raid_end_bio_io(r10_bio);
-       else {
+       else {
                /*
                 * oops, read error:
                 */
@@ -365,8 +362,7 @@ static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, in
  * With this layout, and block is never stored twice on the one device.
  *
  * raid10_find_phys finds the sector offset of a given virtual sector
- * on each device that it is on. If a block isn't on a device,
- * that entry in the array is set to MaxSector.
+ * on each device that it is on.
  *
  * raid10_find_virt does the reverse mapping, from a device and a
  * sector offset to a virtual address
@@ -389,6 +385,8 @@ static void raid10_find_phys(conf_t *conf, r10bio_t *r10bio)
        chunk *= conf->near_copies;
        stripe = chunk;
        dev = sector_div(stripe, conf->raid_disks);
+       if (conf->far_offset)
+               stripe *= conf->far_copies;
 
        sector += stripe << conf->chunk_shift;
 
@@ -422,16 +420,24 @@ static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev)
 {
        sector_t offset, chunk, vchunk;
 
-       while (sector > conf->stride) {
-               sector -= conf->stride;
-               if (dev < conf->near_copies)
-                       dev += conf->raid_disks - conf->near_copies;
-               else
-                       dev -= conf->near_copies;
-       }
-
        offset = sector & conf->chunk_mask;
-       chunk = sector >> conf->chunk_shift;
+       if (conf->far_offset) {
+               int fc;
+               chunk = sector >> conf->chunk_shift;
+               fc = sector_div(chunk, conf->far_copies);
+               dev -= fc * conf->near_copies;
+               if (dev < 0)
+                       dev += conf->raid_disks;
+       } else {
+               while (sector >= conf->stride) {
+                       sector -= conf->stride;
+                       if (dev < conf->near_copies)
+                               dev += conf->raid_disks - conf->near_copies;
+                       else
+                               dev -= conf->near_copies;
+               }
+               chunk = sector >> conf->chunk_shift;
+       }
        vchunk = chunk * conf->raid_disks + dev;
        sector_div(vchunk, conf->near_copies);
        return (vchunk << conf->chunk_shift) + offset;
@@ -506,6 +512,7 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio)
                disk = r10_bio->devs[slot].devnum;
 
                while ((rdev = rcu_dereference(conf->mirrors[disk].rdev)) == NULL ||
+                      r10_bio->devs[slot].bio == IO_BLOCKED ||
                       !test_bit(In_sync, &rdev->flags)) {
                        slot++;
                        if (slot == conf->copies) {
@@ -523,6 +530,7 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio)
        slot = 0;
        disk = r10_bio->devs[slot].devnum;
        while ((rdev=rcu_dereference(conf->mirrors[disk].rdev)) == NULL ||
+              r10_bio->devs[slot].bio == IO_BLOCKED ||
               !test_bit(In_sync, &rdev->flags)) {
                slot ++;
                if (slot == conf->copies) {
@@ -543,6 +551,7 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio)
 
 
                if ((rdev=rcu_dereference(conf->mirrors[ndisk].rdev)) == NULL ||
+                   r10_bio->devs[nslot].bio == IO_BLOCKED ||
                    !test_bit(In_sync, &rdev->flags))
                        continue;
 
@@ -570,6 +579,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;
@@ -637,6 +648,26 @@ static int raid10_issue_flush(request_queue_t *q, struct gendisk *disk,
        return ret;
 }
 
+static int raid10_congested(void *data, int bits)
+{
+       mddev_t *mddev = data;
+       conf_t *conf = mddev_to_conf(mddev);
+       int i, ret = 0;
+
+       rcu_read_lock();
+       for (i = 0; i < mddev->raid_disks && ret == 0; i++) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+               if (rdev && !test_bit(Faulty, &rdev->flags)) {
+                       request_queue_t *q = bdev_get_queue(rdev->bdev);
+
+                       ret |= bdi_congested(&q->backing_dev_info, bits);
+               }
+       }
+       rcu_read_unlock();
+       return ret;
+}
+
+
 /* Barriers....
  * Sometimes we need to suspend IO while we do something else,
  * either some resync/recovery, or reconfigure the array.
@@ -714,6 +745,33 @@ static void allow_barrier(conf_t *conf)
        wake_up(&conf->wait_barrier);
 }
 
+static void freeze_array(conf_t *conf)
+{
+       /* stop syncio and normal IO and wait for everything to
+        * go quiet.
+        * We increment barrier and nr_waiting, and then
+        * wait until barrier+nr_pending match nr_queued+2
+        */
+       spin_lock_irq(&conf->resync_lock);
+       conf->barrier++;
+       conf->nr_waiting++;
+       wait_event_lock_irq(conf->wait_barrier,
+                           conf->barrier+conf->nr_pending == conf->nr_queued+2,
+                           conf->resync_lock,
+                           raid10_unplug(conf->mddev->queue));
+       spin_unlock_irq(&conf->resync_lock);
+}
+
+static void unfreeze_array(conf_t *conf)
+{
+       /* reverse the effect of the freeze */
+       spin_lock_irq(&conf->resync_lock);
+       conf->barrier--;
+       conf->nr_waiting--;
+       wake_up(&conf->wait_barrier);
+       spin_unlock_irq(&conf->resync_lock);
+}
+
 static int make_request(request_queue_t *q, struct bio * bio)
 {
        mddev_t *mddev = q->queuedata;
@@ -724,6 +782,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
        int i;
        int chunk_sects = conf->chunk_mask + 1;
        const int rw = bio_data_dir(bio);
+       const int do_sync = bio_sync(bio);
        struct bio_list bl;
        unsigned long flags;
 
@@ -805,7 +864,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
                        mirror->rdev->data_offset;
                read_bio->bi_bdev = mirror->rdev->bdev;
                read_bio->bi_end_io = raid10_end_read_request;
-               read_bio->bi_rw = READ;
+               read_bio->bi_rw = READ | do_sync;
                read_bio->bi_private = r10_bio;
 
                generic_make_request(read_bio);
@@ -851,7 +910,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
                        conf->mirrors[d].rdev->data_offset;
                mbio->bi_bdev = conf->mirrors[d].rdev->bdev;
                mbio->bi_end_io = raid10_end_write_request;
-               mbio->bi_rw = WRITE;
+               mbio->bi_rw = WRITE | do_sync;
                mbio->bi_private = r10_bio;
 
                atomic_inc(&r10_bio->remaining);
@@ -864,6 +923,9 @@ static int make_request(request_queue_t *q, struct bio * bio)
        blk_plug_device(mddev->queue);
        spin_unlock_irqrestore(&conf->device_lock, flags);
 
+       if (do_sync)
+               md_wakeup_thread(mddev->thread);
+
        return 0;
 }
 
@@ -876,11 +938,14 @@ static void status(struct seq_file *seq, mddev_t *mddev)
                seq_printf(seq, " %dK chunks", mddev->chunk_size/1024);
        if (conf->near_copies > 1)
                seq_printf(seq, " %d near-copies", conf->near_copies);
-       if (conf->far_copies > 1)
-               seq_printf(seq, " %d far-copies", conf->far_copies);
-
+       if (conf->far_copies > 1) {
+               if (conf->far_offset)
+                       seq_printf(seq, " %d offset-copies", conf->far_copies);
+               else
+                       seq_printf(seq, " %d far-copies", conf->far_copies);
+       }
        seq_printf(seq, " [%d/%d] [", conf->raid_disks,
-                                               conf->working_disks);
+                                       conf->raid_disks - mddev->degraded);
        for (i = 0; i < conf->raid_disks; i++)
                seq_printf(seq, "%s",
                              conf->mirrors[i].rdev &&
@@ -900,7 +965,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
         * else mark the drive as failed
         */
        if (test_bit(In_sync, &rdev->flags)
-           && conf->working_disks == 1)
+           && conf->raid_disks-mddev->degraded == 1)
                /*
                 * Don't fail the drive, just return an IO error.
                 * The test should really be more sophisticated than
@@ -909,20 +974,21 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
                 * really dead" tests...
                 */
                return;
-       if (test_bit(In_sync, &rdev->flags)) {
+       if (test_and_clear_bit(In_sync, &rdev->flags)) {
+               unsigned long flags;
+               spin_lock_irqsave(&conf->device_lock, flags);
                mddev->degraded++;
-               conf->working_disks--;
+               spin_unlock_irqrestore(&conf->device_lock, flags);
                /*
                 * if recovery is running, make sure it aborts.
                 */
                set_bit(MD_RECOVERY_ERR, &mddev->recovery);
        }
-       clear_bit(In_sync, &rdev->flags);
        set_bit(Faulty, &rdev->flags);
-       mddev->sb_dirty = 1;
+       set_bit(MD_CHANGE_DEVS, &mddev->flags);
        printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n"
                "       Operation continuing on %d devices\n",
-               bdevname(rdev->bdev,b), conf->working_disks);
+               bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded);
 }
 
 static void print_conf(conf_t *conf)
@@ -935,7 +1001,7 @@ static void print_conf(conf_t *conf)
                printk("(!conf)\n");
                return;
        }
-       printk(" --- wd:%d rd:%d\n", conf->working_disks,
+       printk(" --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded,
                conf->raid_disks);
 
        for (i = 0; i < conf->raid_disks; i++) {
@@ -993,10 +1059,11 @@ static int raid10_spare_active(mddev_t *mddev)
                tmp = conf->mirrors + i;
                if (tmp->rdev
                    && !test_bit(Faulty, &tmp->rdev->flags)
-                   && !test_bit(In_sync, &tmp->rdev->flags)) {
-                       conf->working_disks++;
+                   && !test_and_set_bit(In_sync, &tmp->rdev->flags)) {
+                       unsigned long flags;
+                       spin_lock_irqsave(&conf->device_lock, flags);
                        mddev->degraded--;
-                       set_bit(In_sync, &tmp->rdev->flags);
+                       spin_unlock_irqrestore(&conf->device_lock, flags);
                }
        }
 
@@ -1083,7 +1150,6 @@ abort:
 
 static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
 {
-       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
        conf_t *conf = mddev_to_conf(r10_bio->mddev);
        int i,d;
@@ -1094,13 +1160,19 @@ 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;
-       if (!uptodate)
-               md_error(r10_bio->mddev,
-                        conf->mirrors[d].rdev);
+
+       if (test_bit(BIO_UPTODATE, &bio->bi_flags))
+               set_bit(R10BIO_Uptodate, &r10_bio->state);
+       else {
+               atomic_add(r10_bio->sectors,
+                          &conf->mirrors[d].rdev->corrected_errors);
+               if (!test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery))
+                       md_error(r10_bio->mddev,
+                                conf->mirrors[d].rdev);
+       }
 
        /* for reconstruct, we always reschedule after a read.
         * for resync, only after all reads
@@ -1188,23 +1260,32 @@ static void sync_request_write(mddev_t *mddev, r10bio_t *r10_bio)
        fbio = r10_bio->devs[i].bio;
 
        /* now find blocks with errors */
-       for (i=first+1 ; i < conf->copies ; i++) {
-               int vcnt, j, d;
+       for (i=0 ; i < conf->copies ; i++) {
+               int  j, d;
+               int vcnt = r10_bio->sectors >> (PAGE_SHIFT-9);
 
-               if (!test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags))
-                       continue;
-               /* We know that the bi_io_vec layout is the same for
-                * both 'first' and 'i', so we just compare them.
-                * All vec entries are PAGE_SIZE;
-                */
                tbio = r10_bio->devs[i].bio;
-               vcnt = r10_bio->sectors >> (PAGE_SHIFT-9);
-               for (j = 0; j < vcnt; j++)
-                       if (memcmp(page_address(fbio->bi_io_vec[j].bv_page),
-                                  page_address(tbio->bi_io_vec[j].bv_page),
-                                  PAGE_SIZE))
-                               break;
-               if (j == vcnt)
+
+               if (tbio->bi_end_io != end_sync_read)
+                       continue;
+               if (i == first)
+                       continue;
+               if (test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags)) {
+                       /* We know that the bi_io_vec layout is the same for
+                        * both 'first' and 'i', so we just compare them.
+                        * All vec entries are PAGE_SIZE;
+                        */
+                       for (j = 0; j < vcnt; j++)
+                               if (memcmp(page_address(fbio->bi_io_vec[j].bv_page),
+                                          page_address(tbio->bi_io_vec[j].bv_page),
+                                          PAGE_SIZE))
+                                       break;
+                       if (j == vcnt)
+                               continue;
+                       mddev->resync_mismatches += r10_bio->sectors;
+               }
+               if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
+                       /* Don't fix anything. */
                        continue;
                /* Ok, we need to write this bio
                 * First we need to fixup bv_offset, bv_len and
@@ -1283,7 +1364,10 @@ static void recovery_request_write(mddev_t *mddev, r10bio_t *r10_bio)
 
        atomic_inc(&conf->mirrors[d].rdev->nr_pending);
        md_sync_acct(conf->mirrors[d].rdev->bdev, wbio->bi_size >> 9);
-       generic_make_request(wbio);
+       if (test_bit(R10BIO_Uptodate, &r10_bio->state))
+               generic_make_request(wbio);
+       else
+               bio_endio(wbio, wbio->bi_size, -EIO);
 }
 
 
@@ -1292,9 +1376,119 @@ static void recovery_request_write(mddev_t *mddev, r10bio_t *r10_bio)
  *
  *     1.      Retries failed read operations on working mirrors.
  *     2.      Updates the raid superblock when problems encounter.
- *     3.      Performs writes following reads for array syncronising.
+ *     3.      Performs writes following reads for array synchronising.
  */
 
+static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
+{
+       int sect = 0; /* Offset from r10_bio->sector */
+       int sectors = r10_bio->sectors;
+       mdk_rdev_t*rdev;
+       while(sectors) {
+               int s = sectors;
+               int sl = r10_bio->read_slot;
+               int success = 0;
+               int start;
+
+               if (s > (PAGE_SIZE>>9))
+                       s = PAGE_SIZE >> 9;
+
+               rcu_read_lock();
+               do {
+                       int d = r10_bio->devs[sl].devnum;
+                       rdev = rcu_dereference(conf->mirrors[d].rdev);
+                       if (rdev &&
+                           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) {
+                       /* Cannot read from anywhere -- bye bye array */
+                       int dn = r10_bio->devs[r10_bio->read_slot].devnum;
+                       md_error(mddev, conf->mirrors[dn].rdev);
+                       break;
+               }
+
+               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 = 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;
+               while (sl != r10_bio->read_slot) {
+                       int d;
+                       if (sl==0)
+                               sl = conf->copies;
+                       sl--;
+                       d = r10_bio->devs[sl].devnum;
+                       rdev = rcu_dereference(conf->mirrors[d].rdev);
+                       if (rdev &&
+                           test_bit(In_sync, &rdev->flags)) {
+                               char b[BDEVNAME_SIZE];
+                               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);
+                               else
+                                       printk(KERN_INFO
+                                              "raid10:%s: read error corrected"
+                                              " (%d sectors at %llu on %s)\n",
+                                              mdname(mddev), s,
+                                              (unsigned long long)(sect+
+                                                   rdev->data_offset),
+                                              bdevname(rdev->bdev, b));
+
+                               rdev_dec_pending(rdev, mddev);
+                               rcu_read_lock();
+                       }
+               }
+               rcu_read_unlock();
+
+               sectors -= s;
+               sect += s;
+       }
+}
+
 static void raid10d(mddev_t *mddev)
 {
        r10bio_t *r10_bio;
@@ -1334,6 +1528,7 @@ static void raid10d(mddev_t *mddev)
                        break;
                r10_bio = list_entry(head->prev, r10bio_t, retry_list);
                list_del(head->prev);
+               conf->nr_queued--;
                spin_unlock_irqrestore(&conf->device_lock, flags);
 
                mddev = r10_bio->mddev;
@@ -1346,8 +1541,23 @@ static void raid10d(mddev_t *mddev)
                        unplug = 1;
                } else {
                        int mirror;
+                       /* we got a read error. Maybe the drive is bad.  Maybe just
+                        * the block and we can fix it.
+                        * We freeze all other IO, and try reading the block from
+                        * other devices.  When we find one, we re-write
+                        * and check it that fixes the read error.
+                        * This is all done synchronously while the array is
+                        * frozen.
+                        */
+                       if (mddev->ro == 0) {
+                               freeze_array(conf);
+                               fix_read_error(conf, mddev, r10_bio);
+                               unfreeze_array(conf);
+                       }
+
                        bio = r10_bio->devs[r10_bio->read_slot].bio;
-                       r10_bio->devs[r10_bio->read_slot].bio = NULL;
+                       r10_bio->devs[r10_bio->read_slot].bio =
+                               mddev->ro ? IO_BLOCKED : NULL;
                        bio_put(bio);
                        mirror = read_balance(conf, r10_bio);
                        if (mirror == -1) {
@@ -1357,6 +1567,7 @@ static void raid10d(mddev_t *mddev)
                                       (unsigned long long)r10_bio->sector);
                                raid_end_bio_io(r10_bio);
                        } else {
+                               const int do_sync = bio_sync(r10_bio->master_bio);
                                rdev = conf->mirrors[mirror].rdev;
                                if (printk_ratelimit())
                                        printk(KERN_ERR "raid10: %s: redirecting sector %llu to"
@@ -1368,7 +1579,7 @@ static void raid10d(mddev_t *mddev)
                                bio->bi_sector = r10_bio->devs[r10_bio->read_slot].addr
                                        + rdev->data_offset;
                                bio->bi_bdev = rdev->bdev;
-                               bio->bi_rw = READ;
+                               bio->bi_rw = READ | do_sync;
                                bio->bi_private = r10_bio;
                                bio->bi_end_io = raid10_end_read_request;
                                unplug = 1;
@@ -1387,8 +1598,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;
@@ -1562,8 +1772,10 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                                for (j=0; j<conf->copies;j++) {
                                        int d = r10_bio->devs[j].devnum;
                                        if (conf->mirrors[d].rdev == NULL ||
-                                           test_bit(Faulty, &conf->mirrors[d].rdev->flags))
+                                           test_bit(Faulty, &conf->mirrors[d].rdev->flags)) {
                                                still_degraded = 1;
+                                               break;
+                                       }
                                }
                                must_sync = bitmap_start_sync(mddev->bitmap, sect,
                                                              &sync_blocks, still_degraded);
@@ -1578,7 +1790,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                                                biolist = bio;
                                                bio->bi_private = r10_bio;
                                                bio->bi_end_io = end_sync_read;
-                                               bio->bi_rw = 0;
+                                               bio->bi_rw = READ;
                                                bio->bi_sector = r10_bio->devs[j].addr +
                                                        conf->mirrors[d].rdev->data_offset;
                                                bio->bi_bdev = conf->mirrors[d].rdev->bdev;
@@ -1589,12 +1801,13 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                                                for (k=0; k<conf->copies; k++)
                                                        if (r10_bio->devs[k].devnum == i)
                                                                break;
+                                               BUG_ON(k == conf->copies);
                                                bio = r10_bio->devs[1].bio;
                                                bio->bi_next = biolist;
                                                biolist = bio;
                                                bio->bi_private = r10_bio;
                                                bio->bi_end_io = end_sync_write;
-                                               bio->bi_rw = 1;
+                                               bio->bi_rw = WRITE;
                                                bio->bi_sector = r10_bio->devs[k].addr +
                                                        conf->mirrors[i].rdev->data_offset;
                                                bio->bi_bdev = conf->mirrors[i].rdev->bdev;
@@ -1654,6 +1867,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                        int d = r10_bio->devs[i].devnum;
                        bio = r10_bio->devs[i].bio;
                        bio->bi_end_io = NULL;
+                       clear_bit(BIO_UPTODATE, &bio->bi_flags);
                        if (conf->mirrors[d].rdev == NULL ||
                            test_bit(Faulty, &conf->mirrors[d].rdev->flags))
                                continue;
@@ -1663,7 +1877,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                        biolist = bio;
                        bio->bi_private = r10_bio;
                        bio->bi_end_io = end_sync_read;
-                       bio->bi_rw = 0;
+                       bio->bi_rw = READ;
                        bio->bi_sector = r10_bio->devs[i].addr +
                                conf->mirrors[d].rdev->data_offset;
                        bio->bi_bdev = conf->mirrors[d].rdev->bdev;
@@ -1768,18 +1982,19 @@ static int run(mddev_t *mddev)
        mirror_info_t *disk;
        mdk_rdev_t *rdev;
        struct list_head *tmp;
-       int nc, fc;
+       int nc, fc, fo;
        sector_t stride, size;
 
-       if (mddev->level != 10) {
-               printk(KERN_ERR "raid10: %s: raid level not set correctly... (%d)\n",
-                      mdname(mddev), mddev->level);
-               goto out;
+       if (mddev->chunk_size == 0) {
+               printk(KERN_ERR "md/raid10: non-zero chunk size required.\n");
+               return -EINVAL;
        }
+
        nc = mddev->layout & 255;
        fc = (mddev->layout >> 8) & 255;
+       fo = mddev->layout & (1<<16);
        if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks ||
-           (mddev->layout >> 16)) {
+           (mddev->layout >> 17)) {
                printk(KERN_ERR "raid10: %s: unsupported raid10 layout: 0x%8x\n",
                       mdname(mddev), mddev->layout);
                goto out;
@@ -1789,30 +2004,52 @@ static int run(mddev_t *mddev)
         * bookkeeping area. [whatever we allocate in run(),
         * should be freed in stop()]
         */
-       conf = kmalloc(sizeof(conf_t), GFP_KERNEL);
+       conf = kzalloc(sizeof(conf_t), GFP_KERNEL);
        mddev->private = conf;
        if (!conf) {
                printk(KERN_ERR "raid10: couldn't allocate memory for %s\n",
                        mdname(mddev));
                goto out;
        }
-       memset(conf, 0, sizeof(*conf));
-       conf->mirrors = kmalloc(sizeof(struct mirror_info)*mddev->raid_disks,
+       conf->mirrors = kzalloc(sizeof(struct mirror_info)*mddev->raid_disks,
                                 GFP_KERNEL);
        if (!conf->mirrors) {
                printk(KERN_ERR "raid10: couldn't allocate memory for %s\n",
                       mdname(mddev));
                goto out_free_conf;
        }
-       memset(conf->mirrors, 0, sizeof(struct mirror_info)*mddev->raid_disks);
 
+       conf->tmppage = alloc_page(GFP_KERNEL);
+       if (!conf->tmppage)
+               goto out_free_conf;
+
+       conf->mddev = mddev;
+       conf->raid_disks = mddev->raid_disks;
        conf->near_copies = nc;
        conf->far_copies = fc;
        conf->copies = nc*fc;
+       conf->far_offset = fo;
        conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1;
        conf->chunk_shift = ffz(~mddev->chunk_size) - 9;
-       stride = mddev->size >> (conf->chunk_shift-1);
-       sector_div(stride, fc);
+       size = mddev->size >> (conf->chunk_shift-1);
+       sector_div(size, fc);
+       size = size * conf->raid_disks;
+       sector_div(size, nc);
+       /* 'size' is now the number of chunks in the array */
+       /* calculate "used chunks per device" in 'stride' */
+       stride = size * conf->copies;
+
+       /* We need to round up when dividing by raid_disks to
+        * get the stride size.
+        */
+       stride += conf->raid_disks - 1;
+       sector_div(stride, conf->raid_disks);
+       mddev->size = stride  << (conf->chunk_shift-1);
+
+       if (fo)
+               stride = 1;
+       else
+               sector_div(stride, fc);
        conf->stride = stride << conf->chunk_shift;
 
        conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc,
@@ -1843,11 +2080,7 @@ static int run(mddev_t *mddev)
                        mddev->queue->max_sectors = (PAGE_SIZE>>9);
 
                disk->head_position = 0;
-               if (!test_bit(Faulty, &rdev->flags) && test_bit(In_sync, &rdev->flags))
-                       conf->working_disks++;
        }
-       conf->raid_disks = mddev->raid_disks;
-       conf->mddev = mddev;
        spin_lock_init(&conf->device_lock);
        INIT_LIST_HEAD(&conf->retry_list);
 
@@ -1866,7 +2099,8 @@ static int run(mddev_t *mddev)
 
                disk = conf->mirrors + i;
 
-               if (!disk->rdev) {
+               if (!disk->rdev ||
+                   !test_bit(In_sync, &disk->rdev->flags)) {
                        disk->head_position = 0;
                        mddev->degraded++;
                }
@@ -1888,20 +2122,20 @@ static int run(mddev_t *mddev)
        /*
         * Ok, everything is just fine now
         */
-       size = conf->stride * conf->raid_disks;
-       sector_div(size, conf->near_copies);
-       mddev->array_size = size/2;
-       mddev->resync_max_sectors = size;
+       mddev->array_size = size << (conf->chunk_shift-1);
+       mddev->resync_max_sectors = size << conf->chunk_shift;
 
        mddev->queue->unplug_fn = raid10_unplug;
        mddev->queue->issue_flush_fn = raid10_issue_flush;
+       mddev->queue->backing_dev_info.congested_fn = raid10_congested;
+       mddev->queue->backing_dev_info.congested_data = mddev;
 
        /* Calculate max read-ahead size.
         * We need to readahead at least twice a whole stripe....
         * maybe...
         */
        {
-               int stripe = conf->raid_disks * mddev->chunk_size / PAGE_CACHE_SIZE;
+               int stripe = conf->raid_disks * (mddev->chunk_size / PAGE_SIZE);
                stripe /= conf->near_copies;
                if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
                        mddev->queue->backing_dev_info.ra_pages = 2* stripe;
@@ -1914,6 +2148,7 @@ static int run(mddev_t *mddev)
 out_free_conf:
        if (conf->r10bio_pool)
                mempool_destroy(conf->r10bio_pool);
+       safe_put_page(conf->tmppage);
        kfree(conf->mirrors);
        kfree(conf);
        mddev->private = NULL;
@@ -1957,9 +2192,10 @@ static void raid10_quiesce(mddev_t *mddev, int state)
        }
 }
 
-static mdk_personality_t raid10_personality =
+static struct mdk_personality raid10_personality =
 {
        .name           = "raid10",
+       .level          = 10,
        .owner          = THIS_MODULE,
        .make_request   = make_request,
        .run            = run,
@@ -1975,15 +2211,17 @@ static mdk_personality_t raid10_personality =
 
 static int __init raid_init(void)
 {
-       return register_md_personality(RAID10, &raid10_personality);
+       return register_md_personality(&raid10_personality);
 }
 
 static void raid_exit(void)
 {
-       unregister_md_personality(RAID10);
+       unregister_md_personality(&raid10_personality);
 }
 
 module_init(raid_init);
 module_exit(raid_exit);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("md-personality-9"); /* RAID10 */
+MODULE_ALIAS("md-raid10");
+MODULE_ALIAS("md-level-10");