提交 d787be40 编写于 作者: N NeilBrown 提交者: Shaohua Li

md: reduce the number of synchronize_rcu() calls when multiple devices fail.

Every time a device is removed with ->hot_remove_disk() a synchronize_rcu() call is made
which can delay several milliseconds in some case.
If lots of devices fail at once - as could happen with a large RAID10 where one set
of devices are removed all at once - these delays can add up to be very inconcenient.

As failure is not reversible we can check for that first, setting a
separate flag if it is found, and then all synchronize_rcu() once for
all the flagged devices.  Then ->hot_remove_disk() function can skip the
synchronize_rcu() step if the flag is set.

fix build error(Shaohua)
Signed-off-by: NNeilBrown <neilb@suse.com>
Signed-off-by: NShaohua Li <shli@fb.com>
上级 f5b67ae8
...@@ -8180,15 +8180,34 @@ static int remove_and_add_spares(struct mddev *mddev, ...@@ -8180,15 +8180,34 @@ static int remove_and_add_spares(struct mddev *mddev,
struct md_rdev *rdev; struct md_rdev *rdev;
int spares = 0; int spares = 0;
int removed = 0; int removed = 0;
bool remove_some = false;
rdev_for_each(rdev, mddev) rdev_for_each(rdev, mddev) {
if ((this == NULL || rdev == this) &&
rdev->raid_disk >= 0 &&
!test_bit(Blocked, &rdev->flags) &&
test_bit(Faulty, &rdev->flags) &&
atomic_read(&rdev->nr_pending)==0) {
/* Faulty non-Blocked devices with nr_pending == 0
* never get nr_pending incremented,
* never get Faulty cleared, and never get Blocked set.
* So we can synchronize_rcu now rather than once per device
*/
remove_some = true;
set_bit(RemoveSynchronized, &rdev->flags);
}
}
if (remove_some)
synchronize_rcu();
rdev_for_each(rdev, mddev) {
if ((this == NULL || rdev == this) && if ((this == NULL || rdev == this) &&
rdev->raid_disk >= 0 && rdev->raid_disk >= 0 &&
!test_bit(Blocked, &rdev->flags) && !test_bit(Blocked, &rdev->flags) &&
(test_bit(Faulty, &rdev->flags) || ((test_bit(RemoveSynchronized, &rdev->flags) ||
(!test_bit(In_sync, &rdev->flags) && (!test_bit(In_sync, &rdev->flags) &&
!test_bit(Journal, &rdev->flags))) && !test_bit(Journal, &rdev->flags))) &&
atomic_read(&rdev->nr_pending)==0) { atomic_read(&rdev->nr_pending)==0)) {
if (mddev->pers->hot_remove_disk( if (mddev->pers->hot_remove_disk(
mddev, rdev) == 0) { mddev, rdev) == 0) {
sysfs_unlink_rdev(mddev, rdev); sysfs_unlink_rdev(mddev, rdev);
...@@ -8196,6 +8215,10 @@ static int remove_and_add_spares(struct mddev *mddev, ...@@ -8196,6 +8215,10 @@ static int remove_and_add_spares(struct mddev *mddev,
removed++; removed++;
} }
} }
if (remove_some && test_bit(RemoveSynchronized, &rdev->flags))
clear_bit(RemoveSynchronized, &rdev->flags);
}
if (removed && mddev->kobj.sd) if (removed && mddev->kobj.sd)
sysfs_notify(&mddev->kobj, NULL, "degraded"); sysfs_notify(&mddev->kobj, NULL, "degraded");
......
...@@ -163,6 +163,11 @@ enum flag_bits { ...@@ -163,6 +163,11 @@ enum flag_bits {
* than other devices in the array * than other devices in the array
*/ */
ClusterRemove, ClusterRemove,
RemoveSynchronized, /* synchronize_rcu() was called after
* this device was known to be faulty,
* so it is safe to remove without
* another synchronize_rcu() call.
*/
}; };
static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors, static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors,
......
...@@ -298,12 +298,14 @@ static int multipath_remove_disk(struct mddev *mddev, struct md_rdev *rdev) ...@@ -298,12 +298,14 @@ static int multipath_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
goto abort; goto abort;
} }
p->rdev = NULL; p->rdev = NULL;
synchronize_rcu(); if (!test_bit(RemoveSynchronized, &rdev->flags)) {
if (atomic_read(&rdev->nr_pending)) { synchronize_rcu();
/* lost the race, try later */ if (atomic_read(&rdev->nr_pending)) {
err = -EBUSY; /* lost the race, try later */
p->rdev = rdev; err = -EBUSY;
goto abort; p->rdev = rdev;
goto abort;
}
} }
err = md_integrity_register(mddev); err = md_integrity_register(mddev);
} }
......
...@@ -1656,13 +1656,16 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev) ...@@ -1656,13 +1656,16 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
goto abort; goto abort;
} }
p->rdev = NULL; p->rdev = NULL;
synchronize_rcu(); if (!test_bit(RemoveSynchronized, &rdev->flags)) {
if (atomic_read(&rdev->nr_pending)) { synchronize_rcu();
/* lost the race, try later */ if (atomic_read(&rdev->nr_pending)) {
err = -EBUSY; /* lost the race, try later */
p->rdev = rdev; err = -EBUSY;
goto abort; p->rdev = rdev;
} else if (conf->mirrors[conf->raid_disks + number].rdev) { goto abort;
}
}
if (conf->mirrors[conf->raid_disks + number].rdev) {
/* We just removed a device that is being replaced. /* We just removed a device that is being replaced.
* Move down the replacement. We drain all IO before * Move down the replacement. We drain all IO before
* doing this to avoid confusion. * doing this to avoid confusion.
......
...@@ -1766,7 +1766,7 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev) ...@@ -1766,7 +1766,7 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
err = -EBUSY; err = -EBUSY;
goto abort; goto abort;
} }
/* Only remove faulty devices if recovery /* Only remove non-faulty devices if recovery
* is not possible. * is not possible.
*/ */
if (!test_bit(Faulty, &rdev->flags) && if (!test_bit(Faulty, &rdev->flags) &&
...@@ -1778,13 +1778,16 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev) ...@@ -1778,13 +1778,16 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
goto abort; goto abort;
} }
*rdevp = NULL; *rdevp = NULL;
synchronize_rcu(); if (!test_bit(RemoveSynchronized, &rdev->flags)) {
if (atomic_read(&rdev->nr_pending)) { synchronize_rcu();
/* lost the race, try later */ if (atomic_read(&rdev->nr_pending)) {
err = -EBUSY; /* lost the race, try later */
*rdevp = rdev; err = -EBUSY;
goto abort; *rdevp = rdev;
} else if (p->replacement) { goto abort;
}
}
if (p->replacement) {
/* We must have just cleared 'rdev' */ /* We must have just cleared 'rdev' */
p->rdev = p->replacement; p->rdev = p->replacement;
clear_bit(Replacement, &p->replacement->flags); clear_bit(Replacement, &p->replacement->flags);
......
...@@ -7197,12 +7197,15 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev) ...@@ -7197,12 +7197,15 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
goto abort; goto abort;
} }
*rdevp = NULL; *rdevp = NULL;
synchronize_rcu(); if (!test_bit(RemoveSynchronized, &rdev->flags)) {
if (atomic_read(&rdev->nr_pending)) { synchronize_rcu();
/* lost the race, try later */ if (atomic_read(&rdev->nr_pending)) {
err = -EBUSY; /* lost the race, try later */
*rdevp = rdev; err = -EBUSY;
} else if (p->replacement) { *rdevp = rdev;
}
}
if (p->replacement) {
/* We must have just cleared 'rdev' */ /* We must have just cleared 'rdev' */
p->rdev = p->replacement; p->rdev = p->replacement;
clear_bit(Replacement, &p->replacement->flags); clear_bit(Replacement, &p->replacement->flags);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册