vserver 1.9.3
[linux-2.6.git] / drivers / md / raid6main.c
index 3055f2d..aea1a1b 100644 (file)
@@ -61,7 +61,7 @@
 #define RAID6_DEBUG    0       /* Extremely verbose printk */
 #define RAID6_PARANOIA 1       /* Check spinlocks */
 #define RAID6_DUMPSTATE 0      /* Include stripe cache state in /proc/mdstat */
-#if RAID6_PARANOIA && CONFIG_SMP
+#if RAID6_PARANOIA && defined(CONFIG_SMP)
 # define CHECK_DEVLOCK() if (!spin_is_locked(&conf->device_lock)) BUG()
 #else
 # define CHECK_DEVLOCK()
@@ -414,7 +414,7 @@ static int raid6_end_read_request (struct bio * bi, unsigned int bytes_done,
                md_error(conf->mddev, conf->disks[i].rdev);
                clear_bit(R5_UPTODATE, &sh->dev[i].flags);
        }
-       atomic_dec(&conf->disks[i].rdev->nr_pending);
+       rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
 #if 0
        /* must restore b_page before unlocking buffer... */
        if (sh->bh_page[i] != bh->b_page) {
@@ -457,7 +457,7 @@ static int raid6_end_write_request (struct bio *bi, unsigned int bytes_done,
        if (!uptodate)
                md_error(conf->mddev, conf->disks[i].rdev);
 
-       atomic_dec(&conf->disks[i].rdev->nr_pending);
+       rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
 
        clear_bit(R5_LOCKED, &sh->dev[i].flags);
        set_bit(STRIPE_HANDLE, &sh->state);
@@ -498,8 +498,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
 
        if (!rdev->faulty) {
                mddev->sb_dirty = 1;
-               conf->working_disks--;
                if (rdev->in_sync) {
+                       conf->working_disks--;
                        mddev->degraded++;
                        conf->failed_disks++;
                        rdev->in_sync = 0;
@@ -1157,7 +1157,7 @@ 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 || (syncing && (uptodate+failed < 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) &&
@@ -1208,7 +1208,8 @@ static void handle_stripe(struct stripe_head *sh)
                                        PRINTK("Reading block %d (sync=%d)\n",
                                                i, syncing);
                                        if (syncing)
-                                               md_sync_acct(conf->disks[i].rdev, STRIPE_SECTORS);
+                                               md_sync_acct(conf->disks[i].rdev->bdev,
+                                                            STRIPE_SECTORS);
                                }
                        }
                }
@@ -1418,7 +1419,7 @@ static void handle_stripe(struct stripe_head *sh)
 
                if (rdev) {
                        if (test_bit(R5_Syncio, &sh->dev[i].flags))
-                               md_sync_acct(rdev, STRIPE_SECTORS);
+                               md_sync_acct(rdev->bdev, STRIPE_SECTORS);
 
                        bi->bi_bdev = rdev->bdev;
                        PRINTK("for %llu schedule op %ld on disc %d\n",
@@ -1461,21 +1462,27 @@ static inline void raid6_activate_delayed(raid6_conf_t *conf)
 
 static void unplug_slaves(mddev_t *mddev)
 {
-       /* note: this is always called with device_lock held */
        raid6_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->disks[i].rdev;
-               if (rdev && !rdev->faulty) {
-                       struct block_device *bdev = rdev->bdev;
-                       if (bdev) {
-                               request_queue_t *r_queue = bdev_get_queue(bdev);
-                               if (r_queue && r_queue->unplug_fn)
-                                       r_queue->unplug_fn(r_queue);
-                       }
+               if (rdev && atomic_read(&rdev->nr_pending)) {
+                       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 && 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 raid6_unplug_device(request_queue_t *q)
@@ -1495,6 +1502,39 @@ static void raid6_unplug_device(request_queue_t *q)
        unplug_slaves(mddev);
 }
 
+static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk,
+                            sector_t *error_sector)
+{
+       mddev_t *mddev = q->queuedata;
+       raid6_conf_t *conf = mddev_to_conf(mddev);
+       int i, ret = 0;
+
+       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;
+
+                       if (!bdev)
+                               continue;
+
+                       r_queue = bdev_get_queue(bdev);
+                       if (!r_queue)
+                               continue;
+
+                       if (!r_queue->issue_flush_fn) {
+                               ret = -EOPNOTSUPP;
+                               break;
+                       }
+
+                       ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+                       if (ret)
+                               break;
+               }
+       }
+       return ret;
+}
+
 static inline void raid6_plug_device(raid6_conf_t *conf)
 {
        spin_lock_irq(&conf->device_lock);
@@ -1702,6 +1742,7 @@ static int run (mddev_t *mddev)
        atomic_set(&conf->preread_active_stripes, 0);
 
        mddev->queue->unplug_fn = raid6_unplug_device;
+       mddev->queue->issue_flush_fn = raid6_issue_flush;
 
        PRINTK("raid6: run(%s) called.\n", mdname(mddev));
 
@@ -1735,6 +1776,9 @@ static int run (mddev_t *mddev)
        conf->algorithm = mddev->layout;
        conf->max_nr_stripes = NR_STRIPES;
 
+       /* device size must be a multiple of chunk size */
+       mddev->size &= ~(mddev->chunk_size/1024 -1);
+
        if (conf->raid_disks < 4) {
                printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n",
                       mdname(mddev), conf->raid_disks);
@@ -1991,6 +2035,27 @@ static int raid6_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
        return found;
 }
 
+static int raid6_resize(mddev_t *mddev, sector_t sectors)
+{
+       /* no resync is happening, and there is enough space
+        * on all devices, so we can resize.
+        * We need to make sure resync covers any new space.
+        * If the array is shrinking we should possibly wait until
+        * any io in the removed space completes, but it hardly seems
+        * worth it.
+        */
+       sectors &= ~((sector_t)mddev->chunk_size/512 - 1);
+       mddev->array_size = (sectors * (mddev->raid_disks-2))>>1;
+       set_capacity(mddev->gendisk, mddev->array_size << 1);
+       mddev->changed = 1;
+       if (sectors/2  > mddev->size && mddev->recovery_cp == MaxSector) {
+               mddev->recovery_cp = mddev->size << 1;
+               set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+       }
+       mddev->size = sectors /2;
+       return 0;
+}
+
 static mdk_personality_t raid6_personality=
 {
        .name           = "raid6",
@@ -2004,6 +2069,7 @@ static mdk_personality_t raid6_personality=
        .hot_remove_disk= raid6_remove_disk,
        .spare_active   = raid6_spare_active,
        .sync_request   = sync_request,
+       .resize         = raid6_resize,
 };
 
 static int __init raid6_init (void)