mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-01 10:45:49 +00:00
md: split MD_RECOVERY_NEEDED out of mddev_resume
New mddev_resume() calls are added to synchronize IO with array
reconfiguration, however, this introduces a performance regression while
adding it in md_start_sync():
1) someone sets MD_RECOVERY_NEEDED first;
2) daemon thread grabs reconfig_mutex, then clears MD_RECOVERY_NEEDED and
queues a new sync work;
3) daemon thread releases reconfig_mutex;
4) in md_start_sync
a) check that there are spares that can be added/removed, then suspend
the array;
b) remove_and_add_spares may not be called, or called without really
add/remove spares;
c) resume the array, then set MD_RECOVERY_NEEDED again!
Loop between 2 - 4, then mddev_suspend() will be called quite often, for
consequence, normal IO will be quite slow.
Fix this problem by don't set MD_RECOVERY_NEEDED again in md_start_sync(),
hence the loop will be broken.
Fixes: bc08041b32
("md: suspend array in md_start_sync() if array need reconfiguration")
Suggested-by: Song Liu <song@kernel.org>
Reported-by: Janpieter Sollie <janpieter.sollie@edpnet.be>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218200
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20231207020724.2797445-1-yukuai1@huaweicloud.com
This commit is contained in:
parent
f52f5c71f3
commit
b39113349d
@ -490,7 +490,7 @@ int mddev_suspend(struct mddev *mddev, bool interruptible)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mddev_suspend);
|
||||
|
||||
void mddev_resume(struct mddev *mddev)
|
||||
static void __mddev_resume(struct mddev *mddev, bool recovery_needed)
|
||||
{
|
||||
lockdep_assert_not_held(&mddev->reconfig_mutex);
|
||||
|
||||
@ -507,12 +507,18 @@ void mddev_resume(struct mddev *mddev)
|
||||
percpu_ref_resurrect(&mddev->active_io);
|
||||
wake_up(&mddev->sb_wait);
|
||||
|
||||
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
|
||||
if (recovery_needed)
|
||||
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
|
||||
md_wakeup_thread(mddev->thread);
|
||||
md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
|
||||
|
||||
mutex_unlock(&mddev->suspend_mutex);
|
||||
}
|
||||
|
||||
void mddev_resume(struct mddev *mddev)
|
||||
{
|
||||
return __mddev_resume(mddev, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mddev_resume);
|
||||
|
||||
/*
|
||||
@ -9389,7 +9395,15 @@ static void md_start_sync(struct work_struct *ws)
|
||||
goto not_running;
|
||||
}
|
||||
|
||||
suspend ? mddev_unlock_and_resume(mddev) : mddev_unlock(mddev);
|
||||
mddev_unlock(mddev);
|
||||
/*
|
||||
* md_start_sync was triggered by MD_RECOVERY_NEEDED, so we should
|
||||
* not set it again. Otherwise, we may cause issue like this one:
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=218200
|
||||
* Therefore, use __mddev_resume(mddev, false).
|
||||
*/
|
||||
if (suspend)
|
||||
__mddev_resume(mddev, false);
|
||||
md_wakeup_thread(mddev->sync_thread);
|
||||
sysfs_notify_dirent_safe(mddev->sysfs_action);
|
||||
md_new_event();
|
||||
@ -9401,7 +9415,15 @@ static void md_start_sync(struct work_struct *ws)
|
||||
clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
|
||||
clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
|
||||
clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
|
||||
suspend ? mddev_unlock_and_resume(mddev) : mddev_unlock(mddev);
|
||||
mddev_unlock(mddev);
|
||||
/*
|
||||
* md_start_sync was triggered by MD_RECOVERY_NEEDED, so we should
|
||||
* not set it again. Otherwise, we may cause issue like this one:
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=218200
|
||||
* Therefore, use __mddev_resume(mddev, false).
|
||||
*/
|
||||
if (suspend)
|
||||
__mddev_resume(mddev, false);
|
||||
|
||||
wake_up(&resync_wait);
|
||||
if (test_and_clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery) &&
|
||||
|
Loading…
Reference in New Issue
Block a user