From: NeilBrown neilb@suse.com
commit 480523feae581ab714ba6610388a3b4619a2f695 upstream.
Since commit 4ad23a976413 ("MD: use per-cpu counter for writes_pending"), set_in_sync() is substantially more expensive: it can wait for a full RCU grace period which can be 10s of milliseconds.
So we should only call it when the cost is justified.
md_check_recovery() currently calls set_in_sync() every time it finds anything to do (on non-external active arrays). For an array performing resync or recovery, this will be quite often. Each call will introduce a delay to the md thread, which can noticeable affect IO submission latency.
In md_check_recovery() we only need to call set_in_sync() if 'safemode' was non-zero at entry, meaning that there has been not recent IO. So we save this "safemode was nonzero" state, and only call set_in_sync() if it was non-zero.
This measurably reduces mean and maximum IO submission latency during resync/recovery.
Reported-and-tested-by: Jack Wang jinpu.wang@cloud.ionos.com Fixes: 4ad23a976413 ("MD: use per-cpu counter for writes_pending") Cc: stable@vger.kernel.org (v4.12+) Signed-off-by: NeilBrown neilb@suse.com Signed-off-by: Song Liu songliubraving@fb.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/md/md.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -8811,6 +8811,7 @@ void md_check_recovery(struct mddev *mdd
if (mddev_trylock(mddev)) { int spares = 0; + bool try_set_sync = mddev->safemode != 0;
if (!mddev->external && mddev->safemode == 1) mddev->safemode = 0; @@ -8856,7 +8857,7 @@ void md_check_recovery(struct mddev *mdd } }
- if (!mddev->external && !mddev->in_sync) { + if (try_set_sync && !mddev->external && !mddev->in_sync) { spin_lock(&mddev->lock); set_in_sync(mddev); spin_unlock(&mddev->lock);