From: Li Youhong stop_sync_thread() waits for either MD_RECOVERY_RUNNING to be cleared, or (when MD_RECOVERY_FROZEN is clear) for mddev->sync_seq to change. The sync_seq counter is only incremented when a sync thread is reaped in md_reap_sync_thread(), not on the md_start_sync() not_running path. If the previous sync attempt took the not_running path, sync_seq does not advance. If mddev->thread then queues and runs a new sync in the window between flush_work() and wait_event(), that new sync may start a real sync thread, leaving MD_RECOVERY_RUNNING set while sync_seq is still unchanged. md_idle_sync_thread() then waits until that new sync thread is reaped and sync_seq finally changes, even though it only needs to wait for the current sync attempt to finish. Fix this by incrementing sync_seq on the not_running path as well, so that the wait condition correctly observes the current sync attempt has completed. Fixes: a17d1bca5aba ("md: fix stopping sync thread") Cc: stable@vger.kernel.org Signed-off-by: Li Youhong --- drivers/md/md.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index 68a72513e884..1970c945e597 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -10352,6 +10352,7 @@ 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); + atomic_inc(&mddev->sync_seq); mddev_unlock(mddev); /* * md_start_sync was triggered by MD_RECOVERY_NEEDED, so we should