]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
md/raid1,raid10: fix error-path detection with md_cloned_bio()
authorAbd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
Fri, 1 May 2026 11:46:50 +0000 (13:46 +0200)
committerYu Kuai <yukuai@fygo.io>
Sun, 31 May 2026 11:09:18 +0000 (19:09 +0800)
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>
drivers/md/raid1.c
drivers/md/raid10.c

index 64d970e2ef50fda96a632956c39ffcca52b0fe3e..22458df5069e9d77db6ef262bb6df7714a09f2cd 100644 (file)
@@ -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
index 7dc2a5a127e89355d82914ef4357dae61d1c74c7..b38a0ccd4661a30cc7a5ebd8a63122bc7a51cdcc 100644 (file)
@@ -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;