[PATCH 5/6] md: don't wait for q->limits_lock in mddev_update_io_opt()
From: Jack Wang <jinpu.wang@ionos.com>
Date: 2026-09-07 13:39:40
Also in:
linux-block
Subsystem:
software raid (multiple disks) support, the rest · Maintainers:
Song Liu, Yu Kuai, Linus Torvalds
From: Jack Wang <jinpu.wang@cloud.ionos.com> end_reshape() calls this from the sync thread, and md_reap_sync_thread() waits for that thread with reconfig_mutex held. Waiting for q->limits_lock here hangs a finishing reshape when the lock's holder is waiting for I/O that only md_check_recovery() can complete. Use the trylock and skip the change on a contended pass; io_opt is a hint. Callers that own an update pass it in and have it changed in place. Only the lock leg is addressed; the same cycle also runs through the mddev_suspend() below, which this function has always done from the sync thread. Assisted-by: Claude:claude-opus-5 Signed-off-by: Jack Wang <jinpu.wang@ionos.com> --- drivers/md/md.c | 33 +++++++++++++++++++++++++++------ drivers/md/md.h | 3 ++- drivers/md/raid10.c | 2 +- drivers/md/raid5.c | 2 +- 4 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 8ad6fe178e96..6af11a74db57 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c@@ -6344,19 +6344,40 @@ static bool mddev_stack_limits_trylock(struct mddev *mddev, } /* update the optimal I/O size after a reshape */ -void mddev_update_io_opt(struct mddev *mddev, unsigned int nr_stripes) +void mddev_update_io_opt(struct mddev *mddev, unsigned int nr_stripes, + struct queue_limits *lim) { - struct queue_limits lim; + struct queue_limits own; if (mddev_is_dm(mddev)) return; + /* + * With an update owned by the caller just change it in place; it is + * committed, and the array resumed, by whoever started it. Taking + * q->limits_lock here would nest it inside reconfig_mutex and the + * suspend, which deadlocks, see md_start_sync(). + */ + if (lim) { + lim->io_opt = lim->io_min * nr_stripes; + return; + } + + /* + * Called from the sync thread, which md_reap_sync_thread() waits for + * with reconfig_mutex held, so don't wait for q->limits_lock here. + * io_opt is a hint, skipping it on a contended pass is fine. + */ + if (!mddev_stack_limits_trylock(mddev, &own)) + return; + /* don't bother updating io_opt if we can't suspend the array */ - if (mddev_suspend(mddev, false) < 0) + if (mddev_suspend(mddev, false) < 0) { + queue_limits_cancel_update(mddev->gendisk->queue); return; - lim = queue_limits_start_update(mddev->gendisk->queue); - lim.io_opt = lim.io_min * nr_stripes; - queue_limits_commit_update(mddev->gendisk->queue, &lim); + } + own.io_opt = own.io_min * nr_stripes; + queue_limits_commit_update(mddev->gendisk->queue, &own); mddev_resume(mddev); } EXPORT_SYMBOL_GPL(mddev_update_io_opt);
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 39b95951cc17..9e3bd5ab5519 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h@@ -1050,7 +1050,8 @@ int mddev_stack_rdev_limits(struct mddev *mddev, struct queue_limits *lim, int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev); int mddev_stack_rdev_into(struct mddev *mddev, struct md_rdev *rdev, struct queue_limits *lim); -void mddev_update_io_opt(struct mddev *mddev, unsigned int nr_stripes); +void mddev_update_io_opt(struct mddev *mddev, unsigned int nr_stripes, + struct queue_limits *lim); extern const struct block_device_operations md_fops;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index a5b65f377d04..641619328a6c 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c@@ -4928,7 +4928,7 @@ static void end_reshape(struct r10conf *conf) conf->reshape_safe = MaxSector; spin_unlock_irq(&conf->device_lock); - mddev_update_io_opt(conf->mddev, raid10_nr_stripes(conf)); + mddev_update_io_opt(conf->mddev, raid10_nr_stripes(conf), NULL); conf->fullsync = 0; }
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 0ec555ada64a..3faa2a94c03b 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c@@ -8800,7 +8800,7 @@ static void end_reshape(struct r5conf *conf) wake_up(&conf->wait_for_reshape); mddev_update_io_opt(conf->mddev, - conf->raid_disks - conf->max_degraded); + conf->raid_disks - conf->max_degraded, NULL); } }
--
2.43.0