]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
md/raid1: check bitmap before behind write
authorYu Kuai <yukuai3@huawei.com>
Mon, 7 Jul 2025 01:27:05 +0000 (09:27 +0800)
committerYu Kuai <yukuai3@huawei.com>
Sat, 6 Sep 2025 09:11:58 +0000 (17:11 +0800)
behind write rely on bitmap, because the number of IO are recorded in
bitmap->behind_writes, and callers rely on bitmap_wait_behind_writes()
to wait for IO to be done.

However, currently callers doesn't check if bitmap is enabeld before
calling into behind methods. Hence if behind write start without bitmap,
readers will not wait for slow write IO to be done and old data can be
read in some corner cases.

Link: https://lore.kernel.org/linux-raid/20250707012711.376844-10-yukuai1@huaweicloud.com
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Reviewed-by: Xiao Ni <xni@redhat.com>
drivers/md/md-bitmap.c
drivers/md/raid1.c

index 62b0eac28a7d291a2e38044d622369e167e87e44..29de99e0de3e11cce2ce9ec4b1a6a6e81caf2eda 100644 (file)
@@ -2049,9 +2049,6 @@ static void bitmap_start_behind_write(struct mddev *mddev)
        struct bitmap *bitmap = mddev->bitmap;
        int bw;
 
-       if (!bitmap)
-               return;
-
        atomic_inc(&bitmap->behind_writes);
        bw = atomic_read(&bitmap->behind_writes);
        if (bw > bitmap->behind_writes_used)
@@ -2065,9 +2062,6 @@ static void bitmap_end_behind_write(struct mddev *mddev)
 {
        struct bitmap *bitmap = mddev->bitmap;
 
-       if (!bitmap)
-               return;
-
        if (atomic_dec_and_test(&bitmap->behind_writes))
                wake_up(&bitmap->behind_wait);
        pr_debug("dec write-behind count %d/%lu\n",
index 0864da7d9adcd1c674a2496d0c3865efe6b433da..5599dcbd2991e366c33c305b33c1e63858389853 100644 (file)
@@ -1366,7 +1366,8 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
                                    (unsigned long long)r1_bio->sector,
                                    mirror->rdev->bdev);
 
-       if (test_bit(WriteMostly, &mirror->rdev->flags)) {
+       if (test_bit(WriteMostly, &mirror->rdev->flags) &&
+           md_bitmap_enabled(mddev, false)) {
                /*
                 * Reading from a write-mostly device must take care not to
                 * over-take any writes that are 'behind'
@@ -1452,6 +1453,30 @@ retry:
        return true;
 }
 
+static void raid1_start_write_behind(struct mddev *mddev, struct r1bio *r1_bio,
+                                    struct bio *bio)
+{
+       unsigned long max_write_behind = mddev->bitmap_info.max_write_behind;
+       struct md_bitmap_stats stats;
+       int err;
+
+       /* behind write rely on bitmap, see bitmap_operations */
+       if (!md_bitmap_enabled(mddev, false))
+               return;
+
+       err = mddev->bitmap_ops->get_stats(mddev->bitmap, &stats);
+       if (err)
+               return;
+
+       /* Don't do behind IO if reader is waiting, or there are too many. */
+       if (!stats.behind_wait && stats.behind_writes < max_write_behind)
+               alloc_behind_master_bio(r1_bio, bio);
+
+       if (test_bit(R1BIO_BehindIO, &r1_bio->state))
+               mddev->bitmap_ops->start_behind_write(mddev);
+
+}
+
 static void raid1_write_request(struct mddev *mddev, struct bio *bio,
                                int max_write_sectors)
 {
@@ -1612,22 +1637,8 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
                        continue;
 
                if (first_clone) {
-                       unsigned long max_write_behind =
-                               mddev->bitmap_info.max_write_behind;
-                       struct md_bitmap_stats stats;
-                       int err;
-
-                       /* do behind I/O ?
-                        * Not if there are too many, or cannot
-                        * allocate memory, or a reader on WriteMostly
-                        * is waiting for behind writes to flush */
-                       err = mddev->bitmap_ops->get_stats(mddev->bitmap, &stats);
-                       if (!err && write_behind && !stats.behind_wait &&
-                           stats.behind_writes < max_write_behind)
-                               alloc_behind_master_bio(r1_bio, bio);
-
-                       if (test_bit(R1BIO_BehindIO, &r1_bio->state))
-                               mddev->bitmap_ops->start_behind_write(mddev);
+                       if (write_behind)
+                               raid1_start_write_behind(mddev, r1_bio, bio);
                        first_clone = 0;
                }