dm-raid: delay flushing event_work() after reconfig_mutex is released
authorYu Kuai <yukuai3@huawei.com>
Fri, 24 Nov 2023 07:59:53 +0000 (15:59 +0800)
committerMike Snitzer <snitzer@kernel.org>
Mon, 18 Dec 2023 18:05:21 +0000 (13:05 -0500)
After commit db5e653d7c9f ("md: delay choosing sync action to
md_start_sync()"), md_start_sync() will hold 'reconfig_mutex', however,
in order to make sure event_work is done, __md_stop() will flush
workqueue with reconfig_mutex grabbed, hence if sync_work is still
pending, deadlock will be triggered.

Fortunately, former pacthes to fix stopping sync_thread already make sure
all sync_work is done already, hence such deadlock is not possible
anymore. However, in order not to cause confusions for people by this
implicit dependency, delay flushing event_work to dm-raid where
'reconfig_mutex' is not held, and add some comments to emphasize that
the workqueue can't be flushed with 'reconfig_mutex'.

Fixes: db5e653d7c9f ("md: delay choosing sync action to md_start_sync()")
Depends-on: f52f5c71f3d4 ("md: fix stopping sync thread")
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Acked-by: Xiao Ni <xni@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
drivers/md/dm-raid.c
drivers/md/md.c

index 91ebdcc6e9a8c5088cc828a127b5250319a67773..eb009d6bb03a17b72a06b9a932cd15242be10e26 100644 (file)
@@ -3317,6 +3317,9 @@ static void raid_dtr(struct dm_target *ti)
        mddev_lock_nointr(&rs->md);
        md_stop(&rs->md);
        mddev_unlock(&rs->md);
+
+       if (work_pending(&rs->md.event_work))
+               flush_work(&rs->md.event_work);
        raid_set_free(rs);
 }
 
index b066abbffd10e08f6057156e55487cb172be8437..9bdd57324c37606a37c79b96451858e7b844a64e 100644 (file)
@@ -82,6 +82,14 @@ static struct module *md_cluster_mod;
 
 static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
 static struct workqueue_struct *md_wq;
+
+/*
+ * This workqueue is used for sync_work to register new sync_thread, and for
+ * del_work to remove rdev, and for event_work that is only set by dm-raid.
+ *
+ * Noted that sync_work will grab reconfig_mutex, hence never flush this
+ * workqueue whith reconfig_mutex grabbed.
+ */
 static struct workqueue_struct *md_misc_wq;
 struct workqueue_struct *md_bitmap_wq;
 
@@ -6330,9 +6338,6 @@ static void __md_stop(struct mddev *mddev)
        struct md_personality *pers = mddev->pers;
        md_bitmap_destroy(mddev);
        mddev_detach(mddev);
-       /* Ensure ->event_work is done */
-       if (mddev->event_work.func)
-               flush_workqueue(md_misc_wq);
        spin_lock(&mddev->lock);
        mddev->pers = NULL;
        spin_unlock(&mddev->lock);