diff options
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r-- | drivers/md/md.c | 107 |
1 files changed, 80 insertions, 27 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 5d1b6762f108..ca8527fe77eb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -1713,6 +1713,8 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev) | |||
1713 | } | 1713 | } |
1714 | if (sb->devflags & WriteMostly1) | 1714 | if (sb->devflags & WriteMostly1) |
1715 | set_bit(WriteMostly, &rdev->flags); | 1715 | set_bit(WriteMostly, &rdev->flags); |
1716 | if (le32_to_cpu(sb->feature_map) & MD_FEATURE_REPLACEMENT) | ||
1717 | set_bit(Replacement, &rdev->flags); | ||
1716 | } else /* MULTIPATH are always insync */ | 1718 | } else /* MULTIPATH are always insync */ |
1717 | set_bit(In_sync, &rdev->flags); | 1719 | set_bit(In_sync, &rdev->flags); |
1718 | 1720 | ||
@@ -1766,6 +1768,9 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev) | |||
1766 | sb->recovery_offset = | 1768 | sb->recovery_offset = |
1767 | cpu_to_le64(rdev->recovery_offset); | 1769 | cpu_to_le64(rdev->recovery_offset); |
1768 | } | 1770 | } |
1771 | if (test_bit(Replacement, &rdev->flags)) | ||
1772 | sb->feature_map |= | ||
1773 | cpu_to_le32(MD_FEATURE_REPLACEMENT); | ||
1769 | 1774 | ||
1770 | if (mddev->reshape_position != MaxSector) { | 1775 | if (mddev->reshape_position != MaxSector) { |
1771 | sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE); | 1776 | sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE); |
@@ -2559,6 +2564,15 @@ state_show(struct md_rdev *rdev, char *page) | |||
2559 | len += sprintf(page+len, "%swrite_error", sep); | 2564 | len += sprintf(page+len, "%swrite_error", sep); |
2560 | sep = ","; | 2565 | sep = ","; |
2561 | } | 2566 | } |
2567 | if (test_bit(WantReplacement, &rdev->flags)) { | ||
2568 | len += sprintf(page+len, "%swant_replacement", sep); | ||
2569 | sep = ","; | ||
2570 | } | ||
2571 | if (test_bit(Replacement, &rdev->flags)) { | ||
2572 | len += sprintf(page+len, "%sreplacement", sep); | ||
2573 | sep = ","; | ||
2574 | } | ||
2575 | |||
2562 | return len+sprintf(page+len, "\n"); | 2576 | return len+sprintf(page+len, "\n"); |
2563 | } | 2577 | } |
2564 | 2578 | ||
@@ -2627,6 +2641,42 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len) | |||
2627 | } else if (cmd_match(buf, "-write_error")) { | 2641 | } else if (cmd_match(buf, "-write_error")) { |
2628 | clear_bit(WriteErrorSeen, &rdev->flags); | 2642 | clear_bit(WriteErrorSeen, &rdev->flags); |
2629 | err = 0; | 2643 | err = 0; |
2644 | } else if (cmd_match(buf, "want_replacement")) { | ||
2645 | /* Any non-spare device that is not a replacement can | ||
2646 | * become want_replacement at any time, but we then need to | ||
2647 | * check if recovery is needed. | ||
2648 | */ | ||
2649 | if (rdev->raid_disk >= 0 && | ||
2650 | !test_bit(Replacement, &rdev->flags)) | ||
2651 | set_bit(WantReplacement, &rdev->flags); | ||
2652 | set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery); | ||
2653 | md_wakeup_thread(rdev->mddev->thread); | ||
2654 | err = 0; | ||
2655 | } else if (cmd_match(buf, "-want_replacement")) { | ||
2656 | /* Clearing 'want_replacement' is always allowed. | ||
2657 | * Once replacements starts it is too late though. | ||
2658 | */ | ||
2659 | err = 0; | ||
2660 | clear_bit(WantReplacement, &rdev->flags); | ||
2661 | } else if (cmd_match(buf, "replacement")) { | ||
2662 | /* Can only set a device as a replacement when array has not | ||
2663 | * yet been started. Once running, replacement is automatic | ||
2664 | * from spares, or by assigning 'slot'. | ||
2665 | */ | ||
2666 | if (rdev->mddev->pers) | ||
2667 | err = -EBUSY; | ||
2668 | else { | ||
2669 | set_bit(Replacement, &rdev->flags); | ||
2670 | err = 0; | ||
2671 | } | ||
2672 | } else if (cmd_match(buf, "-replacement")) { | ||
2673 | /* Similarly, can only clear Replacement before start */ | ||
2674 | if (rdev->mddev->pers) | ||
2675 | err = -EBUSY; | ||
2676 | else { | ||
2677 | clear_bit(Replacement, &rdev->flags); | ||
2678 | err = 0; | ||
2679 | } | ||
2630 | } | 2680 | } |
2631 | if (!err) | 2681 | if (!err) |
2632 | sysfs_notify_dirent_safe(rdev->sysfs_state); | 2682 | sysfs_notify_dirent_safe(rdev->sysfs_state); |
@@ -2688,7 +2738,7 @@ slot_store(struct md_rdev *rdev, const char *buf, size_t len) | |||
2688 | if (rdev->mddev->pers->hot_remove_disk == NULL) | 2738 | if (rdev->mddev->pers->hot_remove_disk == NULL) |
2689 | return -EINVAL; | 2739 | return -EINVAL; |
2690 | err = rdev->mddev->pers-> | 2740 | err = rdev->mddev->pers-> |
2691 | hot_remove_disk(rdev->mddev, rdev->raid_disk); | 2741 | hot_remove_disk(rdev->mddev, rdev); |
2692 | if (err) | 2742 | if (err) |
2693 | return err; | 2743 | return err; |
2694 | sysfs_unlink_rdev(rdev->mddev, rdev); | 2744 | sysfs_unlink_rdev(rdev->mddev, rdev); |
@@ -2696,7 +2746,6 @@ slot_store(struct md_rdev *rdev, const char *buf, size_t len) | |||
2696 | set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery); | 2746 | set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery); |
2697 | md_wakeup_thread(rdev->mddev->thread); | 2747 | md_wakeup_thread(rdev->mddev->thread); |
2698 | } else if (rdev->mddev->pers) { | 2748 | } else if (rdev->mddev->pers) { |
2699 | struct md_rdev *rdev2; | ||
2700 | /* Activating a spare .. or possibly reactivating | 2749 | /* Activating a spare .. or possibly reactivating |
2701 | * if we ever get bitmaps working here. | 2750 | * if we ever get bitmaps working here. |
2702 | */ | 2751 | */ |
@@ -2710,10 +2759,6 @@ slot_store(struct md_rdev *rdev, const char *buf, size_t len) | |||
2710 | if (rdev->mddev->pers->hot_add_disk == NULL) | 2759 | if (rdev->mddev->pers->hot_add_disk == NULL) |
2711 | return -EINVAL; | 2760 | return -EINVAL; |
2712 | 2761 | ||
2713 | list_for_each_entry(rdev2, &rdev->mddev->disks, same_set) | ||
2714 | if (rdev2->raid_disk == slot) | ||
2715 | return -EEXIST; | ||
2716 | |||
2717 | if (slot >= rdev->mddev->raid_disks && | 2762 | if (slot >= rdev->mddev->raid_disks && |
2718 | slot >= rdev->mddev->raid_disks + rdev->mddev->delta_disks) | 2763 | slot >= rdev->mddev->raid_disks + rdev->mddev->delta_disks) |
2719 | return -ENOSPC; | 2764 | return -ENOSPC; |
@@ -6053,8 +6098,15 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, | |||
6053 | struct mddev *mddev = NULL; | 6098 | struct mddev *mddev = NULL; |
6054 | int ro; | 6099 | int ro; |
6055 | 6100 | ||
6056 | if (!capable(CAP_SYS_ADMIN)) | 6101 | switch (cmd) { |
6057 | return -EACCES; | 6102 | case RAID_VERSION: |
6103 | case GET_ARRAY_INFO: | ||
6104 | case GET_DISK_INFO: | ||
6105 | break; | ||
6106 | default: | ||
6107 | if (!capable(CAP_SYS_ADMIN)) | ||
6108 | return -EACCES; | ||
6109 | } | ||
6058 | 6110 | ||
6059 | /* | 6111 | /* |
6060 | * Commands dealing with the RAID driver but not any | 6112 | * Commands dealing with the RAID driver but not any |
@@ -6714,8 +6766,11 @@ static int md_seq_show(struct seq_file *seq, void *v) | |||
6714 | if (test_bit(Faulty, &rdev->flags)) { | 6766 | if (test_bit(Faulty, &rdev->flags)) { |
6715 | seq_printf(seq, "(F)"); | 6767 | seq_printf(seq, "(F)"); |
6716 | continue; | 6768 | continue; |
6717 | } else if (rdev->raid_disk < 0) | 6769 | } |
6770 | if (rdev->raid_disk < 0) | ||
6718 | seq_printf(seq, "(S)"); /* spare */ | 6771 | seq_printf(seq, "(S)"); /* spare */ |
6772 | if (test_bit(Replacement, &rdev->flags)) | ||
6773 | seq_printf(seq, "(R)"); | ||
6719 | sectors += rdev->sectors; | 6774 | sectors += rdev->sectors; |
6720 | } | 6775 | } |
6721 | 6776 | ||
@@ -7337,29 +7392,27 @@ static int remove_and_add_spares(struct mddev *mddev) | |||
7337 | ! test_bit(In_sync, &rdev->flags)) && | 7392 | ! test_bit(In_sync, &rdev->flags)) && |
7338 | atomic_read(&rdev->nr_pending)==0) { | 7393 | atomic_read(&rdev->nr_pending)==0) { |
7339 | if (mddev->pers->hot_remove_disk( | 7394 | if (mddev->pers->hot_remove_disk( |
7340 | mddev, rdev->raid_disk)==0) { | 7395 | mddev, rdev) == 0) { |
7341 | sysfs_unlink_rdev(mddev, rdev); | 7396 | sysfs_unlink_rdev(mddev, rdev); |
7342 | rdev->raid_disk = -1; | 7397 | rdev->raid_disk = -1; |
7343 | } | 7398 | } |
7344 | } | 7399 | } |
7345 | 7400 | ||
7346 | if (mddev->degraded) { | 7401 | list_for_each_entry(rdev, &mddev->disks, same_set) { |
7347 | list_for_each_entry(rdev, &mddev->disks, same_set) { | 7402 | if (rdev->raid_disk >= 0 && |
7348 | if (rdev->raid_disk >= 0 && | 7403 | !test_bit(In_sync, &rdev->flags) && |
7349 | !test_bit(In_sync, &rdev->flags) && | 7404 | !test_bit(Faulty, &rdev->flags)) |
7350 | !test_bit(Faulty, &rdev->flags)) | 7405 | spares++; |
7406 | if (rdev->raid_disk < 0 | ||
7407 | && !test_bit(Faulty, &rdev->flags)) { | ||
7408 | rdev->recovery_offset = 0; | ||
7409 | if (mddev->pers-> | ||
7410 | hot_add_disk(mddev, rdev) == 0) { | ||
7411 | if (sysfs_link_rdev(mddev, rdev)) | ||
7412 | /* failure here is OK */; | ||
7351 | spares++; | 7413 | spares++; |
7352 | if (rdev->raid_disk < 0 | 7414 | md_new_event(mddev); |
7353 | && !test_bit(Faulty, &rdev->flags)) { | 7415 | set_bit(MD_CHANGE_DEVS, &mddev->flags); |
7354 | rdev->recovery_offset = 0; | ||
7355 | if (mddev->pers-> | ||
7356 | hot_add_disk(mddev, rdev) == 0) { | ||
7357 | if (sysfs_link_rdev(mddev, rdev)) | ||
7358 | /* failure here is OK */; | ||
7359 | spares++; | ||
7360 | md_new_event(mddev); | ||
7361 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | ||
7362 | } | ||
7363 | } | 7416 | } |
7364 | } | 7417 | } |
7365 | } | 7418 | } |
@@ -7474,7 +7527,7 @@ void md_check_recovery(struct mddev *mddev) | |||
7474 | test_bit(Faulty, &rdev->flags) && | 7527 | test_bit(Faulty, &rdev->flags) && |
7475 | atomic_read(&rdev->nr_pending)==0) { | 7528 | atomic_read(&rdev->nr_pending)==0) { |
7476 | if (mddev->pers->hot_remove_disk( | 7529 | if (mddev->pers->hot_remove_disk( |
7477 | mddev, rdev->raid_disk)==0) { | 7530 | mddev, rdev) == 0) { |
7478 | sysfs_unlink_rdev(mddev, rdev); | 7531 | sysfs_unlink_rdev(mddev, rdev); |
7479 | rdev->raid_disk = -1; | 7532 | rdev->raid_disk = -1; |
7480 | } | 7533 | } |