md:Add support for Raid0->Raid5 takeover
[safe/jmp/linux-2.6] / drivers / md / raid5.c
index 70ffbd0..bb28fd6 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/cpu.h>
 #include "md.h"
 #include "raid5.h"
+#include "raid0.h"
 #include "bitmap.h"
 
 /*
@@ -1618,7 +1619,7 @@ static void raid5_build_block(struct stripe_head *sh, int i, int previous)
 static void error(mddev_t *mddev, mdk_rdev_t *rdev)
 {
        char b[BDEVNAME_SIZE];
-       raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
+       raid5_conf_t *conf = mddev->private;
        pr_debug("raid5: error called\n");
 
        if (!test_bit(Faulty, &rdev->flags)) {
@@ -4057,7 +4058,7 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
         * As the reads complete, handle_stripe will copy the data
         * into the destination stripe and release that stripe.
         */
-       raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
+       raid5_conf_t *conf = mddev->private;
        struct stripe_head *sh;
        sector_t first_sector, last_sector;
        int raid_disks = conf->previous_raid_disks;
@@ -4266,7 +4267,7 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
 /* FIXME go_faster isn't used */
 static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster)
 {
-       raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
+       raid5_conf_t *conf = mddev->private;
        struct stripe_head *sh;
        sector_t max_sector = mddev->dev_sectors;
        int sync_blocks;
@@ -5090,7 +5091,9 @@ static int run(mddev_t *mddev)
        }
 
        /* Ok, everything is just fine now */
-       if (sysfs_create_group(&mddev->kobj, &raid5_attrs_group))
+       if (mddev->to_remove == &raid5_attrs_group)
+               mddev->to_remove = NULL;
+       else if (sysfs_create_group(&mddev->kobj, &raid5_attrs_group))
                printk(KERN_WARNING
                       "raid5: failed to create sysfs attributes for %s\n",
                       mdname(mddev));
@@ -5130,14 +5133,15 @@ abort:
 
 static int stop(mddev_t *mddev)
 {
-       raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
+       raid5_conf_t *conf = mddev->private;
 
        md_unregister_thread(mddev->thread);
        mddev->thread = NULL;
        mddev->queue->backing_dev_info.congested_fn = NULL;
        blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
        free_conf(conf);
-       mddev->private = &raid5_attrs_group;
+       mddev->private = NULL;
+       mddev->to_remove = &raid5_attrs_group;
        return 0;
 }
 
@@ -5178,7 +5182,7 @@ static void printall(struct seq_file *seq, raid5_conf_t *conf)
 
 static void status(struct seq_file *seq, mddev_t *mddev)
 {
-       raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
+       raid5_conf_t *conf = mddev->private;
        int i;
 
        seq_printf(seq, " level %d, %dk chunk, algorithm %d", mddev->level,
@@ -5616,6 +5620,21 @@ static void raid5_quiesce(mddev_t *mddev, int state)
 }
 
 
+static void *raid5_takeover_raid0(mddev_t *mddev)
+{
+
+       mddev->new_level = 5;
+       mddev->new_layout = ALGORITHM_PARITY_N;
+       mddev->new_chunk_sectors = mddev->chunk_sectors;
+       mddev->raid_disks += 1;
+       mddev->delta_disks = 1;
+       /* make sure it will be not marked as dirty */
+       mddev->recovery_cp = MaxSector;
+
+       return setup_conf(mddev);
+}
+
+
 static void *raid5_takeover_raid1(mddev_t *mddev)
 {
        int chunksect;
@@ -5745,6 +5764,16 @@ static void *raid5_takeover(mddev_t *mddev)
         *  raid4 - trivial - just use a raid4 layout.
         *  raid6 - Providing it is a *_6 layout
         */
+       if (mddev->level == 0) {
+               /* for raid0 takeover only one zone is supported */
+               struct raid0_private_data *raid0_priv
+                       = mddev->private;
+               if (raid0_priv->nr_strip_zones > 1) {
+                       printk(KERN_ERR "md: cannot takeover raid 0 with more than one zone.\n");
+                       return ERR_PTR(-EINVAL);
+               }
+               return raid5_takeover_raid0(mddev);
+       }
 
        if (mddev->level == 1)
                return raid5_takeover_raid1(mddev);