aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/md.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2011-12-22 18:17:51 -0500
committerNeilBrown <neilb@suse.de>2011-12-22 18:17:51 -0500
commit2d78f8c451785f030ac1676a18691896b59c69d8 (patch)
tree4dfe69115b2ca2fb8be2a671e7c8399c3925fcb9 /drivers/md/md.c
parentb8321b68d1445f308324517e45fb0a5c2b48e271 (diff)
md: create externally visible flags for supporting hot-replace.
hot-replace is a feature being added to md which will allow a device to be replaced without removing it from the array first. With hot-replace a spare can be activated and recovery can start while the original device is still in place, thus allowing a transition from an unreliable device to a reliable device without leaving the array degraded during the transition. It can also be use when the original device is still reliable but it not wanted for some reason. This will eventually be supported in RAID4/5/6 and RAID10. This patch adds a super-block flag to distinguish the replacement device. If an old kernel sees this flag it will reject the device. It also adds two per-device flags which are viewable and settable via sysfs. "want_replacement" can be set to request that a device be replaced. "replacement" is set to show that this device is replacing another device. The "rd%d" links in /sys/block/mdXx/md only apply to the original device, not the replacement. We currently don't make links for the replacement - there doesn't seem to be a need. Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r--drivers/md/md.c55
1 files changed, 54 insertions, 1 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 0e2288824938..be569eb41a93 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1714,6 +1714,8 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
1714 } 1714 }
1715 if (sb->devflags & WriteMostly1) 1715 if (sb->devflags & WriteMostly1)
1716 set_bit(WriteMostly, &rdev->flags); 1716 set_bit(WriteMostly, &rdev->flags);
1717 if (le32_to_cpu(sb->feature_map) & MD_FEATURE_REPLACEMENT)
1718 set_bit(Replacement, &rdev->flags);
1717 } else /* MULTIPATH are always insync */ 1719 } else /* MULTIPATH are always insync */
1718 set_bit(In_sync, &rdev->flags); 1720 set_bit(In_sync, &rdev->flags);
1719 1721
@@ -1767,6 +1769,9 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
1767 sb->recovery_offset = 1769 sb->recovery_offset =
1768 cpu_to_le64(rdev->recovery_offset); 1770 cpu_to_le64(rdev->recovery_offset);
1769 } 1771 }
1772 if (test_bit(Replacement, &rdev->flags))
1773 sb->feature_map |=
1774 cpu_to_le32(MD_FEATURE_REPLACEMENT);
1770 1775
1771 if (mddev->reshape_position != MaxSector) { 1776 if (mddev->reshape_position != MaxSector) {
1772 sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE); 1777 sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE);
@@ -2560,6 +2565,15 @@ state_show(struct md_rdev *rdev, char *page)
2560 len += sprintf(page+len, "%swrite_error", sep); 2565 len += sprintf(page+len, "%swrite_error", sep);
2561 sep = ","; 2566 sep = ",";
2562 } 2567 }
2568 if (test_bit(WantReplacement, &rdev->flags)) {
2569 len += sprintf(page+len, "%swant_replacement", sep);
2570 sep = ",";
2571 }
2572 if (test_bit(Replacement, &rdev->flags)) {
2573 len += sprintf(page+len, "%sreplacement", sep);
2574 sep = ",";
2575 }
2576
2563 return len+sprintf(page+len, "\n"); 2577 return len+sprintf(page+len, "\n");
2564} 2578}
2565 2579
@@ -2628,6 +2642,42 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
2628 } else if (cmd_match(buf, "-write_error")) { 2642 } else if (cmd_match(buf, "-write_error")) {
2629 clear_bit(WriteErrorSeen, &rdev->flags); 2643 clear_bit(WriteErrorSeen, &rdev->flags);
2630 err = 0; 2644 err = 0;
2645 } else if (cmd_match(buf, "want_replacement")) {
2646 /* Any non-spare device that is not a replacement can
2647 * become want_replacement at any time, but we then need to
2648 * check if recovery is needed.
2649 */
2650 if (rdev->raid_disk >= 0 &&
2651 !test_bit(Replacement, &rdev->flags))
2652 set_bit(WantReplacement, &rdev->flags);
2653 set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
2654 md_wakeup_thread(rdev->mddev->thread);
2655 err = 0;
2656 } else if (cmd_match(buf, "-want_replacement")) {
2657 /* Clearing 'want_replacement' is always allowed.
2658 * Once replacements starts it is too late though.
2659 */
2660 err = 0;
2661 clear_bit(WantReplacement, &rdev->flags);
2662 } else if (cmd_match(buf, "replacement")) {
2663 /* Can only set a device as a replacement when array has not
2664 * yet been started. Once running, replacement is automatic
2665 * from spares, or by assigning 'slot'.
2666 */
2667 if (rdev->mddev->pers)
2668 err = -EBUSY;
2669 else {
2670 set_bit(Replacement, &rdev->flags);
2671 err = 0;
2672 }
2673 } else if (cmd_match(buf, "-replacement")) {
2674 /* Similarly, can only clear Replacement before start */
2675 if (rdev->mddev->pers)
2676 err = -EBUSY;
2677 else {
2678 clear_bit(Replacement, &rdev->flags);
2679 err = 0;
2680 }
2631 } 2681 }
2632 if (!err) 2682 if (!err)
2633 sysfs_notify_dirent_safe(rdev->sysfs_state); 2683 sysfs_notify_dirent_safe(rdev->sysfs_state);
@@ -6717,8 +6767,11 @@ static int md_seq_show(struct seq_file *seq, void *v)
6717 if (test_bit(Faulty, &rdev->flags)) { 6767 if (test_bit(Faulty, &rdev->flags)) {
6718 seq_printf(seq, "(F)"); 6768 seq_printf(seq, "(F)");
6719 continue; 6769 continue;
6720 } else if (rdev->raid_disk < 0) 6770 }
6771 if (rdev->raid_disk < 0)
6721 seq_printf(seq, "(S)"); /* spare */ 6772 seq_printf(seq, "(S)"); /* spare */
6773 if (test_bit(Replacement, &rdev->flags))
6774 seq_printf(seq, "(R)");
6722 sectors += rdev->sectors; 6775 sectors += rdev->sectors;
6723 } 6776 }
6724 6777