patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / md / multipath.c
index 9114c7c..3d87901 100644 (file)
@@ -54,9 +54,8 @@ static void mp_pool_free(void *mpb, void *data)
        kfree(mpb);
 }
 
-static int multipath_map (mddev_t *mddev, mdk_rdev_t **rdevp)
+static int multipath_map (multipath_conf_t *conf)
 {
-       multipath_conf_t *conf = mddev_to_conf(mddev);
        int i, disks = conf->raid_disks;
 
        /*
@@ -68,10 +67,9 @@ static int multipath_map (mddev_t *mddev, mdk_rdev_t **rdevp)
        for (i = 0; i < disks; i++) {
                mdk_rdev_t *rdev = conf->multipaths[i].rdev;
                if (rdev && rdev->in_sync) {
-                       *rdevp = rdev;
                        atomic_inc(&rdev->nr_pending);
                        spin_unlock_irq(&conf->device_lock);
-                       return 0;
+                       return i;
                }
        }
        spin_unlock_irq(&conf->device_lock);
@@ -133,25 +131,7 @@ int multipath_end_request(struct bio *bio, unsigned int bytes_done, int error)
                       (unsigned long long)bio->bi_sector);
                multipath_reschedule_retry(mp_bh);
        }
-       atomic_dec(&rdev->nr_pending);
-       return 0;
-}
-
-/*
- * This routine returns the disk from which the requested read should
- * be done.
- */
-
-static int multipath_read_balance (multipath_conf_t *conf)
-{
-       int disk;
-
-       for (disk = 0; disk < conf->raid_disks; disk++) {
-               mdk_rdev_t *rdev = conf->multipaths[disk].rdev;
-               if (rdev && rdev->in_sync)
-                       return disk;
-       }
-       BUG();
+       rdev_dec_pending(rdev, conf->mddev);
        return 0;
 }
 
@@ -159,16 +139,25 @@ static void unplug_slaves(mddev_t *mddev)
 {
        multipath_conf_t *conf = mddev_to_conf(mddev);
        int i;
+       unsigned long flags;
 
+       spin_lock_irqsave(&conf->device_lock, flags);
        for (i=0; i<mddev->raid_disks; i++) {
                mdk_rdev_t *rdev = conf->multipaths[i].rdev;
                if (rdev && !rdev->faulty) {
                        request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
 
+                       atomic_inc(&rdev->nr_pending);
+                       spin_unlock_irqrestore(&conf->device_lock, flags);
+
                        if (r_queue->unplug_fn)
                                r_queue->unplug_fn(r_queue);
+
+                       spin_lock_irqsave(&conf->device_lock, flags);
+                       atomic_dec(&rdev->nr_pending);
                }
        }
+       spin_unlock_irqrestore(&conf->device_lock, flags);
 }
 static void multipath_unplug(request_queue_t *q)
 {
@@ -195,14 +184,14 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio)
                disk_stat_inc(mddev->gendisk, reads);
                disk_stat_add(mddev->gendisk, read_sectors, bio_sectors(bio));
        }
-       /*
-        * read balancing logic:
-        */
-       spin_lock_irq(&conf->device_lock);
-       mp_bh->path = multipath_read_balance(conf);
+
+       mp_bh->path = multipath_map(conf);
+       if (mp_bh->path < 0) {
+               bio_endio(bio, bio->bi_size, -EIO);
+               mempool_free(mp_bh, conf->pool);
+               return 0;
+       }
        multipath = conf->multipaths + mp_bh->path;
-       atomic_inc(&multipath->rdev->nr_pending);
-       spin_unlock_irq(&conf->device_lock);
 
        mp_bh->bio = *bio;
        mp_bh->bio.bi_bdev = multipath->rdev->bdev;
@@ -366,7 +355,7 @@ static void multipathd (mddev_t *mddev)
        struct multipath_bh *mp_bh;
        struct bio *bio;
        unsigned long flags;
-       mdk_rdev_t *rdev;
+       multipath_conf_t *conf = mddev_to_conf(mddev);
 
        md_check_recovery(mddev);
        for (;;) {
@@ -382,8 +371,7 @@ static void multipathd (mddev_t *mddev)
                bio = &mp_bh->bio;
                bio->bi_sector = mp_bh->master_bio->bi_sector;
                
-               rdev = NULL;
-               if (multipath_map (mddev, &rdev)<0) {
+               if ((mp_bh->path = multipath_map (conf))<0) {
                        printk(KERN_ALERT "multipath: %s: unrecoverable IO read"
                                " error for block %llu\n",
                                bdevname(bio->bi_bdev,b),
@@ -394,7 +382,7 @@ static void multipathd (mddev_t *mddev)
                                " to another IO path\n",
                                bdevname(bio->bi_bdev,b),
                                (unsigned long long)bio->bi_sector);
-                       bio->bi_bdev = rdev->bdev;
+                       bio->bi_bdev = conf->multipaths[mp_bh->path].rdev->bdev;
                        generic_make_request(bio);
                }
        }
@@ -522,6 +510,7 @@ static int multipath_stop (mddev_t *mddev)
        multipath_conf_t *conf = mddev_to_conf(mddev);
 
        md_unregister_thread(mddev->thread);
+       mddev->thread = NULL;
        mempool_destroy(conf->pool);
        kfree(conf->multipaths);
        kfree(conf);