]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
md: factor out sync completion update into helper
authorLi Nan <linan122@huawei.com>
Mon, 5 Jan 2026 11:02:56 +0000 (19:02 +0800)
committerYu Kuai <yukuai@fnnas.com>
Mon, 26 Jan 2026 05:16:21 +0000 (13:16 +0800)
Repeatedly reading 'mddev->recovery' flags in md_do_sync() may introduce
potential risk if this flag is modified during sync, leading to incorrect
offset updates. Therefore, replace direct 'mddev->recovery' checks with
'action'.

Move sync completion update logic into helper md_finish_sync(), which
improves readability and maintainability.

The reshape completion update remains safe as it only updated after
successful reshape when MD_RECOVERY_INTR is not set and 'curr_resync'
equals 'max_sectors'.

Link: https://lore.kernel.org/linux-raid/20260105110300.1442509-9-linan666@huaweicloud.com
Signed-off-by: Li Nan <linan122@huawei.com>
Reviewed-by: Yu Kuai <yukuai@fnnas.com>
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
drivers/md/md.c

index 3ef845af552bbc054f446dae556e95c3fb6935d2..7b4fe7379bb6c5a1df4ecdb0f5f72fd9c8e256d2 100644 (file)
@@ -9438,6 +9438,51 @@ static bool sync_io_within_limit(struct mddev *mddev)
               (raid_is_456(mddev) ? 8 : 128) * sync_io_depth(mddev);
 }
 
+/*
+ * Update sync offset and mddev status when sync completes
+ */
+static void md_finish_sync(struct mddev *mddev, enum sync_action action)
+{
+       struct md_rdev *rdev;
+
+       switch (action) {
+       case ACTION_RESYNC:
+       case ACTION_REPAIR:
+               if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
+                       mddev->curr_resync = MaxSector;
+               mddev->resync_offset = mddev->curr_resync;
+               break;
+       case ACTION_RECOVER:
+               if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
+                       mddev->curr_resync = MaxSector;
+               rcu_read_lock();
+               rdev_for_each_rcu(rdev, mddev)
+                       if (mddev->delta_disks >= 0 &&
+                           rdev_needs_recovery(rdev, mddev->curr_resync))
+                               rdev->recovery_offset = mddev->curr_resync;
+               rcu_read_unlock();
+               break;
+       case ACTION_RESHAPE:
+               if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
+                   mddev->delta_disks > 0 &&
+                   mddev->pers->finish_reshape &&
+                   mddev->pers->size &&
+                   !mddev_is_dm(mddev)) {
+                       mddev_lock_nointr(mddev);
+                       md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0));
+                       mddev_unlock(mddev);
+                       if (!mddev_is_clustered(mddev))
+                               set_capacity_and_notify(mddev->gendisk,
+                                                       mddev->array_sectors);
+               }
+               break;
+       /* */
+       case ACTION_CHECK:
+       default:
+               break;
+       }
+}
+
 #define SYNC_MARKS     10
 #define        SYNC_MARK_STEP  (3*HZ)
 #define UPDATE_FREQUENCY (5*60*HZ)
@@ -9453,7 +9498,6 @@ void md_do_sync(struct md_thread *thread)
        int last_mark,m;
        sector_t last_check;
        int skipped = 0;
-       struct md_rdev *rdev;
        enum sync_action action;
        const char *desc;
        struct blk_plug plug;
@@ -9746,46 +9790,14 @@ update:
        }
        mddev->pers->sync_request(mddev, max_sectors, max_sectors, &skipped);
 
-       if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
-           mddev->curr_resync > MD_RESYNC_ACTIVE) {
-               if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
-                       mddev->curr_resync = MaxSector;
-
-               if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
-                       mddev->resync_offset = mddev->curr_resync;
-               } else {
-                       if (!test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
-                           test_bit(MD_RECOVERY_RECOVER, &mddev->recovery)) {
-                               rcu_read_lock();
-                               rdev_for_each_rcu(rdev, mddev)
-                                       if (mddev->delta_disks >= 0 &&
-                                           rdev_needs_recovery(rdev, mddev->curr_resync))
-                                               rdev->recovery_offset = mddev->curr_resync;
-                               rcu_read_unlock();
-                       }
-               }
-       }
+       if (mddev->curr_resync > MD_RESYNC_ACTIVE)
+               md_finish_sync(mddev, action);
  skip:
        /* set CHANGE_PENDING here since maybe another update is needed,
         * so other nodes are informed. It should be harmless for normal
         * raid */
        set_mask_bits(&mddev->sb_flags, 0,
                      BIT(MD_SB_CHANGE_PENDING) | BIT(MD_SB_CHANGE_DEVS));
-
-       if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
-                       !test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
-                       mddev->delta_disks > 0 &&
-                       mddev->pers->finish_reshape &&
-                       mddev->pers->size &&
-                       !mddev_is_dm(mddev)) {
-               mddev_lock_nointr(mddev);
-               md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0));
-               mddev_unlock(mddev);
-               if (!mddev_is_clustered(mddev))
-                       set_capacity_and_notify(mddev->gendisk,
-                                               mddev->array_sectors);
-       }
-
        spin_lock(&mddev->lock);
        if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
                /* We completed so min/max setting can be forgotten if used. */