This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / md / raid6main.c
index 9a27f8f..9845af2 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/highmem.h>
-#include <linux/bitops.h>
+#include <asm/bitops.h>
 #include <asm/atomic.h>
 #include "raid6.h"
 
@@ -734,6 +734,7 @@ static void compute_parity(struct stripe_head *sh, int method)
        case READ_MODIFY_WRITE:
                BUG();          /* READ_MODIFY_WRITE N/A for RAID-6 */
        case RECONSTRUCT_WRITE:
+       case UPDATE_PARITY:     /* Is this right? */
                for (i= disks; i-- ;)
                        if ( i != pd_idx && i != qd_idx && sh->dev[i].towrite ) {
                                chosen = sh->dev[i].towrite;
@@ -769,8 +770,7 @@ static void compute_parity(struct stripe_head *sh, int method)
                i = d0_idx;
                do {
                        ptrs[count++] = page_address(sh->dev[i].page);
-                       if (count <= disks-2 && !test_bit(R5_UPTODATE, &sh->dev[i].flags))
-                               printk("block %d/%d not uptodate on parity calc\n", i,count);
+
                        i = raid6_next_disk(i, disks);
                } while ( i != d0_idx );
 //             break;
@@ -818,7 +818,7 @@ static void compute_block_1(struct stripe_head *sh, int dd_idx)
                        if (test_bit(R5_UPTODATE, &sh->dev[i].flags))
                                ptr[count++] = p;
                        else
-                               printk("compute_block() %d, stripe %llu, %d"
+                               PRINTK("compute_block() %d, stripe %llu, %d"
                                       " not present\n", dd_idx,
                                       (unsigned long long)sh->sector, i);
 
@@ -875,9 +875,6 @@ static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2)
                do {
                        ptrs[count++] = page_address(sh->dev[i].page);
                        i = raid6_next_disk(i, disks);
-                       if (i != dd_idx1 && i != dd_idx2 &&
-                           !test_bit(R5_UPTODATE, &sh->dev[i].flags))
-                               printk("compute_2 with missing block %d/%d\n", count, i);
                } while ( i != d0_idx );
 
                if ( failb == disks-2 ) {
@@ -1160,15 +1157,17 @@ static void handle_stripe(struct stripe_head *sh)
         * parity, or to satisfy requests
         * or to load a block that is being partially written.
         */
-       if (to_read || non_overwrite || (to_write && failed) || (syncing && (uptodate < disks))) {
+       if (to_read || non_overwrite || (syncing && (uptodate < disks))) {
                for (i=disks; i--;) {
                        dev = &sh->dev[i];
                        if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
                            (dev->toread ||
                             (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
                             syncing ||
-                            (failed >= 1 && (sh->dev[failed_num[0]].toread || to_write)) ||
-                            (failed >= 2 && (sh->dev[failed_num[1]].toread || to_write))
+                            (failed >= 1 && (sh->dev[failed_num[0]].toread ||
+                                        (sh->dev[failed_num[0]].towrite && !test_bit(R5_OVERWRITE, &sh->dev[failed_num[0]].flags)))) ||
+                            (failed >= 2 && (sh->dev[failed_num[1]].toread ||
+                                        (sh->dev[failed_num[1]].towrite && !test_bit(R5_OVERWRITE, &sh->dev[failed_num[1]].flags))))
                                    )
                                ) {
                                /* we would like to get this block, possibly
@@ -1410,13 +1409,13 @@ static void handle_stripe(struct stripe_head *sh)
                else
                        bi->bi_end_io = raid6_end_read_request;
 
-               rcu_read_lock();
+               spin_lock_irq(&conf->device_lock);
                rdev = conf->disks[i].rdev;
                if (rdev && rdev->faulty)
                        rdev = NULL;
                if (rdev)
                        atomic_inc(&rdev->nr_pending);
-               rcu_read_unlock();
+               spin_unlock_irq(&conf->device_lock);
 
                if (rdev) {
                        if (test_bit(R5_Syncio, &sh->dev[i].flags))
@@ -1465,24 +1464,25 @@ static void unplug_slaves(mddev_t *mddev)
 {
        raid6_conf_t *conf = mddev_to_conf(mddev);
        int i;
+       unsigned long flags;
 
-       rcu_read_lock();
+       spin_lock_irqsave(&conf->device_lock, flags);
        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)) {
+               if (rdev && atomic_read(&rdev->nr_pending)) {
                        request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
 
                        atomic_inc(&rdev->nr_pending);
-                       rcu_read_unlock();
+                       spin_unlock_irqrestore(&conf->device_lock, flags);
 
-                       if (r_queue->unplug_fn)
+                       if (r_queue && r_queue->unplug_fn)
                                r_queue->unplug_fn(r_queue);
 
+                       spin_lock_irqsave(&conf->device_lock, flags);
                        rdev_dec_pending(rdev, mddev);
-                       rcu_read_lock();
                }
        }
-       rcu_read_unlock();
+       spin_unlock_irqrestore(&conf->device_lock, flags);
 }
 
 static void raid6_unplug_device(request_queue_t *q)
@@ -1509,26 +1509,29 @@ static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk,
        raid6_conf_t *conf = mddev_to_conf(mddev);
        int i, ret = 0;
 
-       rcu_read_lock();
-       for (i=0; i<mddev->raid_disks && ret == 0; i++) {
+       for (i=0; i<mddev->raid_disks; i++) {
                mdk_rdev_t *rdev = conf->disks[i].rdev;
                if (rdev && !rdev->faulty) {
                        struct block_device *bdev = rdev->bdev;
-                       request_queue_t *r_queue = bdev_get_queue(bdev);
+                       request_queue_t *r_queue;
 
-                       if (!r_queue->issue_flush_fn)
+                       if (!bdev)
+                               continue;
+
+                       r_queue = bdev_get_queue(bdev);
+                       if (!r_queue)
+                               continue;
+
+                       if (!r_queue->issue_flush_fn) {
                                ret = -EOPNOTSUPP;
-                       else {
-                               atomic_inc(&rdev->nr_pending);
-                               rcu_read_unlock();
-                               ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk,
-                                                             error_sector);
-                               rdev_dec_pending(rdev, mddev);
-                               rcu_read_lock();
+                               break;
                        }
+
+                       ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+                       if (ret)
+                               break;
                }
        }
-       rcu_read_unlock();
        return ret;
 }
 
@@ -1570,7 +1573,7 @@ static int make_request (request_queue_t *q, struct bio * bi)
                new_sector = raid6_compute_sector(logical_sector,
                                                  raid_disks, data_disks, &dd_idx, &pd_idx, conf);
 
-               PRINTK("raid6: make_request, sector %llu logical %llu\n",
+               PRINTK("raid6: make_request, sector %Lu logical %Lu\n",
                       (unsigned long long)new_sector,
                       (unsigned long long)logical_sector);
 
@@ -1878,7 +1881,6 @@ static int stop (mddev_t *mddev)
        mddev->thread = NULL;
        shrink_stripes(conf);
        free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER);
-       blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
        kfree(conf);
        mddev->private = NULL;
        return 0;
@@ -1966,6 +1968,7 @@ static int raid6_spare_active(mddev_t *mddev)
        raid6_conf_t *conf = mddev->private;
        struct disk_info *tmp;
 
+       spin_lock_irq(&conf->device_lock);
        for (i = 0; i < conf->raid_disks; i++) {
                tmp = conf->disks + i;
                if (tmp->rdev
@@ -1977,6 +1980,7 @@ static int raid6_spare_active(mddev_t *mddev)
                        tmp->rdev->in_sync = 1;
                }
        }
+       spin_unlock_irq(&conf->device_lock);
        print_raid6_conf(conf);
        return 0;
 }
@@ -1984,29 +1988,25 @@ static int raid6_spare_active(mddev_t *mddev)
 static int raid6_remove_disk(mddev_t *mddev, int number)
 {
        raid6_conf_t *conf = mddev->private;
-       int err = 0;
-       mdk_rdev_t *rdev;
+       int err = 1;
        struct disk_info *p = conf->disks + number;
 
        print_raid6_conf(conf);
-       rdev = p->rdev;
-       if (rdev) {
-               if (rdev->in_sync ||
-                   atomic_read(&rdev->nr_pending)) {
+       spin_lock_irq(&conf->device_lock);
+
+       if (p->rdev) {
+               if (p->rdev->in_sync ||
+                   atomic_read(&p->rdev->nr_pending)) {
                        err = -EBUSY;
                        goto abort;
                }
                p->rdev = NULL;
-               synchronize_kernel();
-               if (atomic_read(&rdev->nr_pending)) {
-                       /* lost the race, try later */
-                       err = -EBUSY;
-                       p->rdev = rdev;
-               }
+               err = 0;
        }
-
+       if (err)
+               MD_BUG();
 abort:
-
+       spin_unlock_irq(&conf->device_lock);
        print_raid6_conf(conf);
        return err;
 }
@@ -2018,17 +2018,19 @@ static int raid6_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
        int disk;
        struct disk_info *p;
 
+       spin_lock_irq(&conf->device_lock);
        /*
         * find the disk ...
         */
        for (disk=0; disk < mddev->raid_disks; disk++)
                if ((p=conf->disks + disk)->rdev == NULL) {
+                       p->rdev = rdev;
                        rdev->in_sync = 0;
                        rdev->raid_disk = disk;
                        found = 1;
-                       p->rdev = rdev;
                        break;
                }
+       spin_unlock_irq(&conf->device_lock);
        print_raid6_conf(conf);
        return found;
 }