aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/md.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2009-03-30 23:39:39 -0400
committerNeilBrown <neilb@suse.de>2009-03-30 23:39:39 -0400
commit245f46c2c221ef09c7db892f0e3fc2149be42052 (patch)
treebe7e6f4b7b65b682c43e59ef17f7ed580bc8a82b /drivers/md/md.c
parent409c57f3801701dfee27a28103dda4831306cb20 (diff)
md: add ->takeover method to support changing the personality managing an array
Implement this for RAID6 to be able to 'takeover' a RAID5 array. The new RAID6 will use a layout which places Q on the last device, and that device will be missing. If there are any available spares, one will immediately have Q recovered onto it. Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r--drivers/md/md.c101
1 files changed, 92 insertions, 9 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 6cb31f8da14c..05b613b5e4b2 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -2649,18 +2649,101 @@ level_show(mddev_t *mddev, char *page)
2649static ssize_t 2649static ssize_t
2650level_store(mddev_t *mddev, const char *buf, size_t len) 2650level_store(mddev_t *mddev, const char *buf, size_t len)
2651{ 2651{
2652 char level[16];
2652 ssize_t rv = len; 2653 ssize_t rv = len;
2653 if (mddev->pers) 2654 struct mdk_personality *pers;
2655 void *priv;
2656
2657 if (mddev->pers == NULL) {
2658 if (len == 0)
2659 return 0;
2660 if (len >= sizeof(mddev->clevel))
2661 return -ENOSPC;
2662 strncpy(mddev->clevel, buf, len);
2663 if (mddev->clevel[len-1] == '\n')
2664 len--;
2665 mddev->clevel[len] = 0;
2666 mddev->level = LEVEL_NONE;
2667 return rv;
2668 }
2669
2670 /* request to change the personality. Need to ensure:
2671 * - array is not engaged in resync/recovery/reshape
2672 * - old personality can be suspended
2673 * - new personality will access other array.
2674 */
2675
2676 if (mddev->sync_thread || mddev->reshape_position != MaxSector)
2654 return -EBUSY; 2677 return -EBUSY;
2655 if (len == 0) 2678
2656 return 0; 2679 if (!mddev->pers->quiesce) {
2657 if (len >= sizeof(mddev->clevel)) 2680 printk(KERN_WARNING "md: %s: %s does not support online personality change\n",
2658 return -ENOSPC; 2681 mdname(mddev), mddev->pers->name);
2659 strncpy(mddev->clevel, buf, len); 2682 return -EINVAL;
2660 if (mddev->clevel[len-1] == '\n') 2683 }
2684
2685 /* Now find the new personality */
2686 if (len == 0 || len >= sizeof(level))
2687 return -EINVAL;
2688 strncpy(level, buf, len);
2689 if (level[len-1] == '\n')
2661 len--; 2690 len--;
2662 mddev->clevel[len] = 0; 2691 level[len] = 0;
2663 mddev->level = LEVEL_NONE; 2692
2693 request_module("md-%s", level);
2694 spin_lock(&pers_lock);
2695 pers = find_pers(LEVEL_NONE, level);
2696 if (!pers || !try_module_get(pers->owner)) {
2697 spin_unlock(&pers_lock);
2698 printk(KERN_WARNING "md: personality %s not loaded\n", level);
2699 return -EINVAL;
2700 }
2701 spin_unlock(&pers_lock);
2702
2703 if (pers == mddev->pers) {
2704 /* Nothing to do! */
2705 module_put(pers->owner);
2706 return rv;
2707 }
2708 if (!pers->takeover) {
2709 module_put(pers->owner);
2710 printk(KERN_WARNING "md: %s: %s does not support personality takeover\n",
2711 mdname(mddev), level);
2712 return -EINVAL;
2713 }
2714
2715 /* ->takeover must set new_* and/or delta_disks
2716 * if it succeeds, and may set them when it fails.
2717 */
2718 priv = pers->takeover(mddev);
2719 if (IS_ERR(priv)) {
2720 mddev->new_level = mddev->level;
2721 mddev->new_layout = mddev->layout;
2722 mddev->new_chunk = mddev->chunk_size;
2723 mddev->raid_disks -= mddev->delta_disks;
2724 mddev->delta_disks = 0;
2725 module_put(pers->owner);
2726 printk(KERN_WARNING "md: %s: %s would not accept array\n",
2727 mdname(mddev), level);
2728 return PTR_ERR(priv);
2729 }
2730
2731 /* Looks like we have a winner */
2732 mddev_suspend(mddev);
2733 mddev->pers->stop(mddev);
2734 module_put(mddev->pers->owner);
2735 mddev->pers = pers;
2736 mddev->private = priv;
2737 strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
2738 mddev->level = mddev->new_level;
2739 mddev->layout = mddev->new_layout;
2740 mddev->chunk_size = mddev->new_chunk;
2741 mddev->delta_disks = 0;
2742 pers->run(mddev);
2743 mddev_resume(mddev);
2744 set_bit(MD_CHANGE_DEVS, &mddev->flags);
2745 set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
2746 md_wakeup_thread(mddev->thread);
2664 return rv; 2747 return rv;
2665} 2748}
2666 2749