[PATCH] md: fix --re-add for raid1 and raid6
[linux-2.6-microblaze.git] / drivers / md / raid6main.c
index 7757869..0000d16 100644 (file)
@@ -507,19 +507,19 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
        raid6_conf_t *conf = (raid6_conf_t *) mddev->private;
        PRINTK("raid6: error called\n");
 
-       if (!rdev->faulty) {
+       if (!test_bit(Faulty, &rdev->flags)) {
                mddev->sb_dirty = 1;
-               if (rdev->in_sync) {
+               if (test_bit(In_sync, &rdev->flags)) {
                        conf->working_disks--;
                        mddev->degraded++;
                        conf->failed_disks++;
-                       rdev->in_sync = 0;
+                       clear_bit(In_sync, &rdev->flags);
                        /*
                         * if recovery was running, make sure it aborts.
                         */
                        set_bit(MD_RECOVERY_ERR, &mddev->recovery);
                }
-               rdev->faulty = 1;
+               set_bit(Faulty, &rdev->flags);
                printk (KERN_ALERT
                        "raid6: Disk failure on %s, disabling device."
                        " Operation continuing on %d devices\n",
@@ -1071,7 +1071,7 @@ static void handle_stripe(struct stripe_head *sh)
                }
                if (dev->written) written++;
                rdev = conf->disks[i].rdev; /* FIXME, should I be looking rdev */
-               if (!rdev || !rdev->in_sync) {
+               if (!rdev || !test_bit(In_sync, &rdev->flags)) {
                        if ( failed < 2 )
                                failed_num[failed] = i;
                        failed++;
@@ -1464,8 +1464,8 @@ static void handle_stripe(struct stripe_head *sh)
                        bi->bi_end_io = raid6_end_read_request;
 
                rcu_read_lock();
-               rdev = conf->disks[i].rdev;
-               if (rdev && rdev->faulty)
+               rdev = rcu_dereference(conf->disks[i].rdev);
+               if (rdev && test_bit(Faulty, &rdev->flags))
                        rdev = NULL;
                if (rdev)
                        atomic_inc(&rdev->nr_pending);
@@ -1538,8 +1538,8 @@ static void unplug_slaves(mddev_t *mddev)
 
        rcu_read_lock();
        for (i=0; i<mddev->raid_disks; i++) {
-               mdk_rdev_t *rdev = conf->disks[i].rdev;
-               if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+               if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
                        request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
 
                        atomic_inc(&rdev->nr_pending);
@@ -1583,8 +1583,8 @@ static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk,
 
        rcu_read_lock();
        for (i=0; i<mddev->raid_disks && ret == 0; i++) {
-               mdk_rdev_t *rdev = conf->disks[i].rdev;
-               if (rdev && !rdev->faulty) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+               if (rdev && !test_bit(Faulty, &rdev->flags)) {
                        struct block_device *bdev = rdev->bdev;
                        request_queue_t *r_queue = bdev_get_queue(bdev);
 
@@ -1702,6 +1702,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
        int data_disks = raid_disks - 2;
        sector_t max_sector = mddev->size << 1;
        int sync_blocks;
+       int still_degraded = 0;
+       int i;
 
        if (sector_nr >= max_sector) {
                /* just being told to finish up .. nothing much to do */
@@ -1710,7 +1712,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                if (mddev->curr_resync < max_sector) /* aborted */
                        bitmap_end_sync(mddev->bitmap, mddev->curr_resync,
                                        &sync_blocks, 1);
-               else /* compelted sync */
+               else /* completed sync */
                        conf->fullsync = 0;
                bitmap_close_sync(mddev->bitmap);
 
@@ -1748,7 +1750,16 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                 */
                schedule_timeout_uninterruptible(1);
        }
-       bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 0);
+       /* Need to check if array will still be degraded after recovery/resync
+        * We don't need to check the 'failed' flag as when that gets set,
+        * recovery aborts.
+        */
+       for (i=0; i<mddev->raid_disks; i++)
+               if (conf->disks[i].rdev == NULL)
+                       still_degraded = 1;
+
+       bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded);
+
        spin_lock(&sh->lock);
        set_bit(STRIPE_SYNCING, &sh->state);
        clear_bit(STRIPE_INSYNC, &sh->state);
@@ -1784,7 +1795,9 @@ static void raid6d (mddev_t *mddev)
 
                if (conf->seq_flush - conf->seq_write > 0) {
                        int seq = conf->seq_flush;
+                       spin_unlock_irq(&conf->device_lock);
                        bitmap_unplug(mddev->bitmap);
+                       spin_lock_irq(&conf->device_lock);
                        conf->seq_write = seq;
                        activate_bit_delay(conf);
                }
@@ -1868,7 +1881,7 @@ static int run(mddev_t *mddev)
 
                disk->rdev = rdev;
 
-               if (rdev->in_sync) {
+               if (test_bit(In_sync, &rdev->flags)) {
                        char b[BDEVNAME_SIZE];
                        printk(KERN_INFO "raid6: device %s operational as raid"
                               " disk %d\n", bdevname(rdev->bdev,b),
@@ -2052,7 +2065,7 @@ static void status (struct seq_file *seq, mddev_t *mddev)
        for (i = 0; i < conf->raid_disks; i++)
                seq_printf (seq, "%s",
                            conf->disks[i].rdev &&
-                           conf->disks[i].rdev->in_sync ? "U" : "_");
+                           test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_");
        seq_printf (seq, "]");
 #if RAID6_DUMPSTATE
        seq_printf (seq, "\n");
@@ -2078,7 +2091,7 @@ static void print_raid6_conf (raid6_conf_t *conf)
                tmp = conf->disks + i;
                if (tmp->rdev)
                printk(" disk %d, o:%d, dev:%s\n",
-                       i, !tmp->rdev->faulty,
+                       i, !test_bit(Faulty, &tmp->rdev->flags),
                        bdevname(tmp->rdev->bdev,b));
        }
 }
@@ -2092,12 +2105,12 @@ static int raid6_spare_active(mddev_t *mddev)
        for (i = 0; i < conf->raid_disks; i++) {
                tmp = conf->disks + i;
                if (tmp->rdev
-                   && !tmp->rdev->faulty
-                   && !tmp->rdev->in_sync) {
+                   && !test_bit(Faulty, &tmp->rdev->flags)
+                   && !test_bit(In_sync, &tmp->rdev->flags)) {
                        mddev->degraded--;
                        conf->failed_disks--;
                        conf->working_disks++;
-                       tmp->rdev->in_sync = 1;
+                       set_bit(In_sync, &tmp->rdev->flags);
                }
        }
        print_raid6_conf(conf);
@@ -2114,7 +2127,7 @@ static int raid6_remove_disk(mddev_t *mddev, int number)
        print_raid6_conf(conf);
        rdev = p->rdev;
        if (rdev) {
-               if (rdev->in_sync ||
+               if (test_bit(In_sync, &rdev->flags) ||
                    atomic_read(&rdev->nr_pending)) {
                        err = -EBUSY;
                        goto abort;
@@ -2145,16 +2158,22 @@ static int raid6_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
                /* no point adding a device */
                return 0;
        /*
-        * find the disk ...
+        * find the disk ... but prefer rdev->saved_raid_disk
+        * if possible.
         */
-       for (disk=0; disk < mddev->raid_disks; disk++)
+       if (rdev->saved_raid_disk >= 0 &&
+           conf->disks[rdev->saved_raid_disk].rdev == NULL)
+               disk = rdev->saved_raid_disk;
+       else
+               disk = 0;
+       for ( ; disk < mddev->raid_disks; disk++)
                if ((p=conf->disks + disk)->rdev == NULL) {
-                       rdev->in_sync = 0;
+                       clear_bit(In_sync, &rdev->flags);
                        rdev->raid_disk = disk;
                        found = 1;
                        if (rdev->saved_raid_disk != disk)
                                conf->fullsync = 1;
-                       p->rdev = rdev;
+                       rcu_assign_pointer(p->rdev, rdev);
                        break;
                }
        print_raid6_conf(conf);