aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2013-04-23 21:42:41 -0400
committerNeilBrown <neilb@suse.de>2013-04-23 21:42:41 -0400
commit746d3207ae2f9cf71fd87c9df884aa104fdaafa6 (patch)
tree6ce6cc0b1d9f147bbc2e3b72cf6e52da922d2f7f /drivers
parentd87f064f5874ba60814c6ccac67104761be5b26c (diff)
md: use common code for all calls to ->hot_remove_disk()
slot_store and remove_and_add_spares both call ->hot_remove_disk(), but with slightly different tests and consequences, which is at least untidy and might be buggy. So modify remove_and_add_spaces() so that it can be asked to remove a specific device, and call it from slot_store(). We also clear the Blocked flag to ensure that doesn't prevent removal. The purpose of Blocked is to prevent automatic removal by the kernel before an error is acknowledged. If the array is read/write then user-space would have not reason to remove a device unless it was known to be 'spare' or 'faulty' in which it would have already cleared the Blocked flag. If the array is read-only, the flag might still be blocked, but there is no harm in clearing the flag for read-only arrays. Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/md.c25
1 files changed, 16 insertions, 9 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index c6e44a836a53..07f207e53ba9 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -72,6 +72,9 @@ static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
72static struct workqueue_struct *md_wq; 72static struct workqueue_struct *md_wq;
73static struct workqueue_struct *md_misc_wq; 73static struct workqueue_struct *md_misc_wq;
74 74
75static int remove_and_add_spares(struct mddev *mddev,
76 struct md_rdev *this);
77
75#define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); } 78#define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); }
76 79
77/* 80/*
@@ -2805,12 +2808,10 @@ slot_store(struct md_rdev *rdev, const char *buf, size_t len)
2805 /* personality does all needed checks */ 2808 /* personality does all needed checks */
2806 if (rdev->mddev->pers->hot_remove_disk == NULL) 2809 if (rdev->mddev->pers->hot_remove_disk == NULL)
2807 return -EINVAL; 2810 return -EINVAL;
2808 err = rdev->mddev->pers-> 2811 clear_bit(Blocked, &rdev->flags);
2809 hot_remove_disk(rdev->mddev, rdev); 2812 remove_and_add_spares(rdev->mddev, rdev);
2810 if (err) 2813 if (rdev->raid_disk >= 0)
2811 return err; 2814 return -EBUSY;
2812 sysfs_unlink_rdev(rdev->mddev, rdev);
2813 rdev->raid_disk = -1;
2814 set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery); 2815 set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
2815 md_wakeup_thread(rdev->mddev->thread); 2816 md_wakeup_thread(rdev->mddev->thread);
2816 } else if (rdev->mddev->pers) { 2817 } else if (rdev->mddev->pers) {
@@ -7649,14 +7650,16 @@ void md_do_sync(struct md_thread *thread)
7649} 7650}
7650EXPORT_SYMBOL_GPL(md_do_sync); 7651EXPORT_SYMBOL_GPL(md_do_sync);
7651 7652
7652static int remove_and_add_spares(struct mddev *mddev) 7653static int remove_and_add_spares(struct mddev *mddev,
7654 struct md_rdev *this)
7653{ 7655{
7654 struct md_rdev *rdev; 7656 struct md_rdev *rdev;
7655 int spares = 0; 7657 int spares = 0;
7656 int removed = 0; 7658 int removed = 0;
7657 7659
7658 rdev_for_each(rdev, mddev) 7660 rdev_for_each(rdev, mddev)
7659 if (rdev->raid_disk >= 0 && 7661 if ((this == NULL || rdev == this) &&
7662 rdev->raid_disk >= 0 &&
7660 !test_bit(Blocked, &rdev->flags) && 7663 !test_bit(Blocked, &rdev->flags) &&
7661 (test_bit(Faulty, &rdev->flags) || 7664 (test_bit(Faulty, &rdev->flags) ||
7662 ! test_bit(In_sync, &rdev->flags)) && 7665 ! test_bit(In_sync, &rdev->flags)) &&
@@ -7671,6 +7674,9 @@ static int remove_and_add_spares(struct mddev *mddev)
7671 if (removed && mddev->kobj.sd) 7674 if (removed && mddev->kobj.sd)
7672 sysfs_notify(&mddev->kobj, NULL, "degraded"); 7675 sysfs_notify(&mddev->kobj, NULL, "degraded");
7673 7676
7677 if (this)
7678 goto no_add;
7679
7674 rdev_for_each(rdev, mddev) { 7680 rdev_for_each(rdev, mddev) {
7675 if (rdev->raid_disk >= 0 && 7681 if (rdev->raid_disk >= 0 &&
7676 !test_bit(In_sync, &rdev->flags) && 7682 !test_bit(In_sync, &rdev->flags) &&
@@ -7689,6 +7695,7 @@ static int remove_and_add_spares(struct mddev *mddev)
7689 } 7695 }
7690 } 7696 }
7691 } 7697 }
7698no_add:
7692 if (removed) 7699 if (removed)
7693 set_bit(MD_CHANGE_DEVS, &mddev->flags); 7700 set_bit(MD_CHANGE_DEVS, &mddev->flags);
7694 return spares; 7701 return spares;
@@ -7872,7 +7879,7 @@ void md_check_recovery(struct mddev *mddev)
7872 goto unlock; 7879 goto unlock;
7873 set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery); 7880 set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
7874 clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery); 7881 clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
7875 } else if ((spares = remove_and_add_spares(mddev))) { 7882 } else if ((spares = remove_and_add_spares(mddev, NULL))) {
7876 clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); 7883 clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
7877 clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); 7884 clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
7878 clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); 7885 clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);