Skip to content

Commit

Permalink
md: use common code for all calls to ->hot_remove_disk()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
NeilBrown committed Apr 24, 2013
1 parent d87f064 commit 746d320
Showing 1 changed file with 16 additions and 9 deletions.
25 changes: 16 additions & 9 deletions drivers/md/md.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
static struct workqueue_struct *md_wq;
static struct workqueue_struct *md_misc_wq;

static int remove_and_add_spares(struct mddev *mddev,
struct md_rdev *this);

#define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); }

/*
Expand Down Expand Up @@ -2805,12 +2808,10 @@ slot_store(struct md_rdev *rdev, const char *buf, size_t len)
/* personality does all needed checks */
if (rdev->mddev->pers->hot_remove_disk == NULL)
return -EINVAL;
err = rdev->mddev->pers->
hot_remove_disk(rdev->mddev, rdev);
if (err)
return err;
sysfs_unlink_rdev(rdev->mddev, rdev);
rdev->raid_disk = -1;
clear_bit(Blocked, &rdev->flags);
remove_and_add_spares(rdev->mddev, rdev);
if (rdev->raid_disk >= 0)
return -EBUSY;
set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
md_wakeup_thread(rdev->mddev->thread);
} else if (rdev->mddev->pers) {
Expand Down Expand Up @@ -7649,14 +7650,16 @@ void md_do_sync(struct md_thread *thread)
}
EXPORT_SYMBOL_GPL(md_do_sync);

static int remove_and_add_spares(struct mddev *mddev)
static int remove_and_add_spares(struct mddev *mddev,
struct md_rdev *this)
{
struct md_rdev *rdev;
int spares = 0;
int removed = 0;

rdev_for_each(rdev, mddev)
if (rdev->raid_disk >= 0 &&
if ((this == NULL || rdev == this) &&
rdev->raid_disk >= 0 &&
!test_bit(Blocked, &rdev->flags) &&
(test_bit(Faulty, &rdev->flags) ||
! test_bit(In_sync, &rdev->flags)) &&
Expand All @@ -7671,6 +7674,9 @@ static int remove_and_add_spares(struct mddev *mddev)
if (removed && mddev->kobj.sd)
sysfs_notify(&mddev->kobj, NULL, "degraded");

if (this)
goto no_add;

rdev_for_each(rdev, mddev) {
if (rdev->raid_disk >= 0 &&
!test_bit(In_sync, &rdev->flags) &&
Expand All @@ -7689,6 +7695,7 @@ static int remove_and_add_spares(struct mddev *mddev)
}
}
}
no_add:
if (removed)
set_bit(MD_CHANGE_DEVS, &mddev->flags);
return spares;
Expand Down Expand Up @@ -7872,7 +7879,7 @@ void md_check_recovery(struct mddev *mddev)
goto unlock;
set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
} else if ((spares = remove_and_add_spares(mddev))) {
} else if ((spares = remove_and_add_spares(mddev, NULL))) {
clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
Expand Down

0 comments on commit 746d320

Please sign in to comment.