OSDN Git Service

md: refactor action_store() for 'idle' and 'frozen'
authorYu Kuai <yukuai3@huawei.com>
Mon, 29 May 2023 13:20:33 +0000 (21:20 +0800)
committerSong Liu <song@kernel.org>
Thu, 27 Jul 2023 07:13:28 +0000 (00:13 -0700)
Prepare to handle 'idle' and 'frozen' differently to fix a deadlock, there
are no functional changes except that MD_RECOVERY_RUNNING is checked
again after 'reconfig_mutex' is held.

Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20230529132037.2124527-3-yukuai1@huaweicloud.com
drivers/md/md.c

index d445d5f..7fa91f0 100644 (file)
@@ -4747,6 +4747,46 @@ action_show(struct mddev *mddev, char *page)
        return sprintf(page, "%s\n", type);
 }
 
+static void stop_sync_thread(struct mddev *mddev)
+{
+       if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+               return;
+
+       if (mddev_lock(mddev))
+               return;
+
+       /*
+        * Check again in case MD_RECOVERY_RUNNING is cleared before lock is
+        * held.
+        */
+       if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
+               mddev_unlock(mddev);
+               return;
+       }
+
+       if (work_pending(&mddev->del_work))
+               flush_workqueue(md_misc_wq);
+
+       if (mddev->sync_thread) {
+               set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+               md_reap_sync_thread(mddev);
+       }
+
+       mddev_unlock(mddev);
+}
+
+static void idle_sync_thread(struct mddev *mddev)
+{
+       clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+       stop_sync_thread(mddev);
+}
+
+static void frozen_sync_thread(struct mddev *mddev)
+{
+       set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+       stop_sync_thread(mddev);
+}
+
 static ssize_t
 action_store(struct mddev *mddev, const char *page, size_t len)
 {
@@ -4754,22 +4794,11 @@ action_store(struct mddev *mddev, const char *page, size_t len)
                return -EINVAL;
 
 
-       if (cmd_match(page, "idle") || cmd_match(page, "frozen")) {
-               if (cmd_match(page, "frozen"))
-                       set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
-               else
-                       clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
-               if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&
-                   mddev_lock(mddev) == 0) {
-                       if (work_pending(&mddev->del_work))
-                               flush_workqueue(md_misc_wq);
-                       if (mddev->sync_thread) {
-                               set_bit(MD_RECOVERY_INTR, &mddev->recovery);
-                               md_reap_sync_thread(mddev);
-                       }
-                       mddev_unlock(mddev);
-               }
-       } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+       if (cmd_match(page, "idle"))
+               idle_sync_thread(mddev);
+       else if (cmd_match(page, "frozen"))
+               frozen_sync_thread(mddev);
+       else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
                return -EBUSY;
        else if (cmd_match(page, "resync"))
                clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);