Thread (18 messages) flat view 18 messages, 6 authors, 17h ago
HOTtoday

[PATCH 3/6] md: don't wait for q->limits_lock in check_sb_changes()

From: Jack Wang <jinpu.wang@ionos.com>
Date: 2026-09-07 13:39:37
Also in: linux-raid
Subsystem: software raid (multiple disks) support, the rest · Maintainers: Song Liu, Yu Kuai, Linus Torvalds

From: Jack Wang <jinpu.wang@cloud.ionos.com>

check_sb_changes() activates a spare added by another node, with
reconfig_mutex held, from md_reload_sb().  Stacking that leg's limits
waits for q->limits_lock while holding the mutex, and the lock's holder
waits for I/O that can be waiting for a superblock update needing the
same mutex.

Take the update without blocking and keep the activation inline.  On a
contended pass only remove; MD_RECOVERY_NEEDED is set below, so
md_start_sync() does the add.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Jack Wang <jinpu.wang@ionos.com>
---
 drivers/md/md.c | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 28fc903ffeea..c7d1f9813f5d 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -6310,6 +6310,20 @@ int mddev_stack_rdev_into(struct mddev *mddev, struct md_rdev *rdev,
 }
 EXPORT_SYMBOL_GPL(mddev_stack_rdev_into);
 
+/* for callers that must not wait for q->limits_lock, see md_start_sync() */
+static bool mddev_stack_limits_trylock(struct mddev *mddev,
+				       struct queue_limits *lim)
+{
+	struct request_queue *q;
+
+	if (mddev_is_dm(mddev))
+		return false;
+
+	q = mddev->gendisk->queue;
+
+	return queue_limits_start_update_trylock(q, lim);
+}
+
 /* update the optimal I/O size after a reshape */
 void mddev_update_io_opt(struct mddev *mddev, unsigned int nr_stripes)
 {
@@ -10829,6 +10843,7 @@ static int __init md_init(void)
 
 static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev)
 {
+	struct queue_limits lim;
 	struct mdp_superblock_1 *sb = page_address(rdev->sb_page);
 	struct md_rdev *rdev2, *tmp;
 	int role, ret;
@@ -10885,7 +10900,24 @@ static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev)
 					rdev2->saved_raid_disk = -1;
 				else
 					rdev2->saved_raid_disk = role;
-				ret = remove_and_add_spares(mddev, rdev2, NULL);
+				/*
+				 * reconfig_mutex is held, so don't wait for
+				 * q->limits_lock; MD_RECOVERY_NEEDED below
+				 * leaves a skipped add to md_start_sync().
+				 */
+				if (mddev_stack_limits_trylock(mddev, &lim)) {
+					struct request_queue *q =
+						mddev->gendisk->queue;
+
+					ret = remove_and_add_spares(mddev,
+								    rdev2, &lim);
+					queue_limits_commit_update(q, &lim);
+				} else if (mddev_is_dm(mddev)) {
+					ret = remove_and_add_spares(mddev,
+								    rdev2, NULL);
+				} else {
+					ret = remove_spares(mddev, rdev2);
+				}
 				pr_info("Activated spare: %pg\n",
 					rdev2->bdev);
 				/* wakeup mddev->thread here, so array could
-- 
2.43.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help