diff options
-rw-r--r-- | drivers/md/md.c | 7 | ||||
-rw-r--r-- | drivers/md/raid0.c | 125 | ||||
-rw-r--r-- | drivers/md/raid0.h | 3 |
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 | ||
26 | static void raid0_unplug(struct request_queue *q) | 27 | static 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 | ||
93 | static int create_strip_zones(mddev_t *mddev) | 94 | static 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; |
269 | abort: | 275 | abort: |
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 | ||
322 | static int raid0_run(mddev_t *mddev) | 328 | static 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 | ||
569 | static 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 | |||
600 | static 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 | |||
638 | static 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 | |||
658 | static void raid0_quiesce(mddev_t *mddev, int state) | ||
659 | { | ||
660 | } | ||
661 | |||
551 | static struct mdk_personality raid0_personality= | 662 | static 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 | ||
563 | static int __init raid0_init (void) | 676 | static 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 | ||
18 | typedef struct raid0_private_data raid0_conf_t; | 21 | typedef struct raid0_private_data raid0_conf_t; |