summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAbd-Alrhman Masalkhi <abd.masalkhi@gmail.com>2026-05-01 13:46:50 +0200
committerYu Kuai <yukuai@fygo.io>2026-05-31 19:09:18 +0800
commit811545e0926d02a6a0b1a1258bb5544777c164d4 (patch)
tree44b96e0a7366df5db87cb6b092f80e2a7d830e9a /drivers
parent7b15c24f805339a585cfe7d72f446b7e88b9bcc0 (diff)
downloadlinux-next-811545e0926d02a6a0b1a1258bb5544777c164d4.tar.gz
linux-next-811545e0926d02a6a0b1a1258bb5544777c164d4.zip
md/raid1,raid10: fix error-path detection with md_cloned_bio()
Detect the error path using md_cloned_bio() instead of relying on r1_bio in raid1 or r10_bio->read_slot in raid10, which may be NULL or -1 after splitting and resubmitting a failed bio. As a result, the error path may not be recognized and memory allocations can incorrectly use GFP_NOIO instead of (GFP_NOIO | __GFP_HIGH), which can lead to a deadlock under memory pressure. Fixes: 689389a06ce7 ("md/raid1: simplify handle_read_error().") Fixes: 545250f24809 ("md/raid10: simplify handle_read_error()") Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com> Reviewed-by: Xiao Ni <xiao@kernel.org> Link: https://patch.msgid.link/20260501114652.590037-3-abd.masalkhi@gmail.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/raid1.c13
-rw-r--r--drivers/md/raid10.c20
2 files changed, 24 insertions, 9 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 64d970e2ef50..22458df5069e 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1343,11 +1343,18 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
bool r1bio_existed = !!r1_bio;
/*
- * If r1_bio is set, we are blocking the raid1d thread
- * so there is a tiny risk of deadlock. So ask for
+ * An md cloned bio indicates we are in the error path.
+ * This is more reliable than checking r1_bio, which might
+ * be NULL even in the error path if a failed bio was split.
+ */
+ bool err_path = md_cloned_bio(mddev, bio);
+
+ /*
+ * If we are in the error path, we are blocking the raid1d
+ * thread so there is a tiny risk of deadlock. So ask for
* emergency memory if needed.
*/
- gfp_t gfp = r1_bio ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
+ gfp_t gfp = err_path ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
/*
* Still need barrier for READ in case that whole
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 7dc2a5a127e8..b38a0ccd4661 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1155,7 +1155,20 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
char b[BDEVNAME_SIZE];
int slot = r10_bio->read_slot;
struct md_rdev *err_rdev = NULL;
- gfp_t gfp = GFP_NOIO;
+
+ /*
+ * An md cloned bio indicates we are in the error path.
+ * This is more reliable than checking slot, which might
+ * be -1 even in the error path if a failed bio was split.
+ */
+ bool err_path = md_cloned_bio(mddev, bio);
+
+ /*
+ * If we are in the error path, we are blocking the raid10d
+ * thread so there is a tiny risk of deadlock. So ask for
+ * emergency memory if needed.
+ */
+ gfp_t gfp = err_path ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
if (slot >= 0 && r10_bio->devs[slot].rdev) {
/*
@@ -1166,11 +1179,6 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
* we lose the device name in error messages.
*/
int disk;
- /*
- * As we are blocking raid10, it is a little safer to
- * use __GFP_HIGH.
- */
- gfp = GFP_NOIO | __GFP_HIGH;
disk = r10_bio->devs[slot].devnum;
err_rdev = conf->mirrors[disk].rdev;