aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrela, Maciej <Maciej.Trela@intel.com>2010-03-08 00:02:44 -0500
committerNeilBrown <neilb@suse.de>2010-05-18 01:27:48 -0400
commit9af204cf720cedf369cf823bbd806c350201f7ea (patch)
tree6aa684772cc1ba978e9dd0f67c3e0d5592588ca3
parent54071b3808ee3dc8624d9d6f1b06c4fd5308fa3b (diff)
md: Add support for Raid5->Raid0 and Raid10->Raid0 takeover
Signed-off-by: Maciej Trela <maciej.trela@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r--drivers/md/md.c7
-rw-r--r--drivers/md/raid0.c125
-rw-r--r--drivers/md/raid0.h3
3 files changed, 129 insertions, 6 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 22c630b7ba6c..7dcc74089550 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3045,6 +3045,13 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
3045 mddev->layout = mddev->new_layout; 3045 mddev->layout = mddev->new_layout;
3046 mddev->chunk_sectors = mddev->new_chunk_sectors; 3046 mddev->chunk_sectors = mddev->new_chunk_sectors;
3047 mddev->delta_disks = 0; 3047 mddev->delta_disks = 0;
3048 if (mddev->pers->sync_request == NULL) {
3049 /* this is now an array without redundancy, so
3050 * it must always be in_sync
3051 */
3052 mddev->in_sync = 1;
3053 del_timer_sync(&mddev->safemode_timer);
3054 }
3048 pers->run(mddev); 3055 pers->run(mddev);
3049 mddev_resume(mddev); 3056 mddev_resume(mddev);
3050 set_bit(MD_CHANGE_DEVS, &mddev->flags); 3057 set_bit(MD_CHANGE_DEVS, &mddev->flags);
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index c2e0d1d28102..afddf624bad3 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -22,6 +22,7 @@
22#include <linux/seq_file.h> 22#include <linux/seq_file.h>
23#include "md.h" 23#include "md.h"
24#include "raid0.h" 24#include "raid0.h"
25#include "raid5.h"
25 26
26static void raid0_unplug(struct request_queue *q) 27static void raid0_unplug(struct request_queue *q)
27{ 28{
@@ -90,7 +91,7 @@ static void dump_zones(mddev_t *mddev)
90 printk(KERN_INFO "**********************************\n\n"); 91 printk(KERN_INFO "**********************************\n\n");
91} 92}
92 93
93static int create_strip_zones(mddev_t *mddev) 94static int create_strip_zones(mddev_t *mddev, raid0_conf_t **private_conf)
94{ 95{
95 int i, c, err; 96 int i, c, err;
96 sector_t curr_zone_end, sectors; 97 sector_t curr_zone_end, sectors;
@@ -164,6 +165,10 @@ static int create_strip_zones(mddev_t *mddev)
164 list_for_each_entry(rdev1, &mddev->disks, same_set) { 165 list_for_each_entry(rdev1, &mddev->disks, same_set) {
165 int j = rdev1->raid_disk; 166 int j = rdev1->raid_disk;
166 167
168 if (mddev->level == 10)
169 /* taking over a raid10-n2 array */
170 j /= 2;
171
167 if (j < 0 || j >= mddev->raid_disks) { 172 if (j < 0 || j >= mddev->raid_disks) {
168 printk(KERN_ERR "raid0: bad disk number %d - " 173 printk(KERN_ERR "raid0: bad disk number %d - "
169 "aborting!\n", j); 174 "aborting!\n", j);
@@ -264,13 +269,14 @@ static int create_strip_zones(mddev_t *mddev)
264 (mddev->chunk_sectors << 9) * mddev->raid_disks); 269 (mddev->chunk_sectors << 9) * mddev->raid_disks);
265 270
266 printk(KERN_INFO "raid0: done.\n"); 271 printk(KERN_INFO "raid0: done.\n");
267 mddev->private = conf; 272 *private_conf = conf;
273
268 return 0; 274 return 0;
269abort: 275abort:
270 kfree(conf->strip_zone); 276 kfree(conf->strip_zone);
271 kfree(conf->devlist); 277 kfree(conf->devlist);
272 kfree(conf); 278 kfree(conf);
273 mddev->private = NULL; 279 *private_conf = NULL;
274 return err; 280 return err;
275} 281}
276 282
@@ -321,6 +327,7 @@ static sector_t raid0_size(mddev_t *mddev, sector_t sectors, int raid_disks)
321 327
322static int raid0_run(mddev_t *mddev) 328static int raid0_run(mddev_t *mddev)
323{ 329{
330 raid0_conf_t *conf;
324 int ret; 331 int ret;
325 332
326 if (mddev->chunk_sectors == 0) { 333 if (mddev->chunk_sectors == 0) {
@@ -332,9 +339,20 @@ static int raid0_run(mddev_t *mddev)
332 blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors); 339 blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors);
333 mddev->queue->queue_lock = &mddev->queue->__queue_lock; 340 mddev->queue->queue_lock = &mddev->queue->__queue_lock;
334 341
335 ret = create_strip_zones(mddev); 342 /* if private is not null, we are here after takeover */
336 if (ret < 0) 343 if (mddev->private == NULL) {
337 return ret; 344 ret = create_strip_zones(mddev, &conf);
345 if (ret < 0)
346 return ret;
347 mddev->private = conf;
348 }
349 conf = mddev->private;
350 if (conf->scale_raid_disks) {
351 int i;
352 for (i=0; i < conf->strip_zone[0].nb_dev; i++)
353 conf->devlist[i]->raid_disk /= conf->scale_raid_disks;
354 /* FIXME update sysfs rd links */
355 }
338 356
339 /* calculate array device size */ 357 /* calculate array device size */
340 md_set_array_sectors(mddev, raid0_size(mddev, 0, 0)); 358 md_set_array_sectors(mddev, raid0_size(mddev, 0, 0));
@@ -548,6 +566,99 @@ static void raid0_status(struct seq_file *seq, mddev_t *mddev)
548 return; 566 return;
549} 567}
550 568
569static void *raid0_takeover_raid5(mddev_t *mddev)
570{
571 mdk_rdev_t *rdev;
572 raid0_conf_t *priv_conf;
573
574 if (mddev->degraded != 1) {
575 printk(KERN_ERR "md: raid5 must be degraded! Degraded disks: %d\n",
576 mddev->degraded);
577 return ERR_PTR(-EINVAL);
578 }
579
580 list_for_each_entry(rdev, &mddev->disks, same_set) {
581 /* check slot number for a disk */
582 if (rdev->raid_disk == mddev->raid_disks-1) {
583 printk(KERN_ERR "md: raid5 must have missing parity disk!\n");
584 return ERR_PTR(-EINVAL);
585 }
586 }
587
588 /* Set new parameters */
589 mddev->new_level = 0;
590 mddev->new_chunk_sectors = mddev->chunk_sectors;
591 mddev->raid_disks--;
592 mddev->delta_disks = -1;
593 /* make sure it will be not marked as dirty */
594 mddev->recovery_cp = MaxSector;
595
596 create_strip_zones(mddev, &priv_conf);
597 return priv_conf;
598}
599
600static void *raid0_takeover_raid10(mddev_t *mddev)
601{
602 raid0_conf_t *priv_conf;
603
604 /* Check layout:
605 * - far_copies must be 1
606 * - near_copies must be 2
607 * - disks number must be even
608 * - all mirrors must be already degraded
609 */
610 if (mddev->layout != ((1 << 8) + 2)) {
611 printk(KERN_ERR "md: Raid0 cannot takover layout: %x\n",
612 mddev->layout);
613 return ERR_PTR(-EINVAL);
614 }
615 if (mddev->raid_disks & 1) {
616 printk(KERN_ERR "md: Raid0 cannot takover Raid10 with odd disk number.\n");
617 return ERR_PTR(-EINVAL);
618 }
619 if (mddev->degraded != (mddev->raid_disks>>1)) {
620 printk(KERN_ERR "md: All mirrors must be already degraded!\n");
621 return ERR_PTR(-EINVAL);
622 }
623
624 /* Set new parameters */
625 mddev->new_level = 0;
626 mddev->new_chunk_sectors = mddev->chunk_sectors;
627 mddev->delta_disks = - mddev->raid_disks / 2;
628 mddev->raid_disks += mddev->delta_disks;
629 mddev->degraded = 0;
630 /* make sure it will be not marked as dirty */
631 mddev->recovery_cp = MaxSector;
632
633 create_strip_zones(mddev, &priv_conf);
634 priv_conf->scale_raid_disks = 2;
635 return priv_conf;
636}
637
638static void *raid0_takeover(mddev_t *mddev)
639{
640 /* raid0 can take over:
641 * raid5 - providing it is Raid4 layout and one disk is faulty
642 * raid10 - assuming we have all necessary active disks
643 */
644 if (mddev->level == 5) {
645 if (mddev->layout == ALGORITHM_PARITY_N)
646 return raid0_takeover_raid5(mddev);
647
648 printk(KERN_ERR "md: Raid can only takeover Raid5 with layout: %d\n",
649 ALGORITHM_PARITY_N);
650 }
651
652 if (mddev->level == 10)
653 return raid0_takeover_raid10(mddev);
654
655 return ERR_PTR(-EINVAL);
656}
657
658static void raid0_quiesce(mddev_t *mddev, int state)
659{
660}
661
551static struct mdk_personality raid0_personality= 662static struct mdk_personality raid0_personality=
552{ 663{
553 .name = "raid0", 664 .name = "raid0",
@@ -558,6 +669,8 @@ static struct mdk_personality raid0_personality=
558 .stop = raid0_stop, 669 .stop = raid0_stop,
559 .status = raid0_status, 670 .status = raid0_status,
560 .size = raid0_size, 671 .size = raid0_size,
672 .takeover = raid0_takeover,
673 .quiesce = raid0_quiesce,
561}; 674};
562 675
563static int __init raid0_init (void) 676static int __init raid0_init (void)
diff --git a/drivers/md/raid0.h b/drivers/md/raid0.h
index 91f8e876ee64..d724e664ca4d 100644
--- a/drivers/md/raid0.h
+++ b/drivers/md/raid0.h
@@ -13,6 +13,9 @@ struct raid0_private_data
13 struct strip_zone *strip_zone; 13 struct strip_zone *strip_zone;
14 mdk_rdev_t **devlist; /* lists of rdevs, pointed to by strip_zone->dev */ 14 mdk_rdev_t **devlist; /* lists of rdevs, pointed to by strip_zone->dev */
15 int nr_strip_zones; 15 int nr_strip_zones;
16 int scale_raid_disks; /* divide rdev->raid_disks by this in run()
17 * to handle conversion from raid10
18 */
16}; 19};
17 20
18typedef struct raid0_private_data raid0_conf_t; 21typedef struct raid0_private_data raid0_conf_t;