dm-delay: fix workqueue delay_timer race
authorBenjamin Marzinski <bmarzins@redhat.com>
Tue, 7 May 2024 21:16:23 +0000 (17:16 -0400)
committerMike Snitzer <snitzer@kernel.org>
Thu, 9 May 2024 13:10:58 +0000 (09:10 -0400)
delay_timer could be pending when delay_dtr() is called. It needs to be
shut down before kdelayd_wq is destroyed, so it won't try queueing more
work to kdelayd_wq while that's getting destroyed.

Also the del_timer_sync() call in delay_presuspend() doesn't protect
against the timer getting immediately rearmed by the queued call to
flush_delayed_bios(), but there's no real harm if that does happen.
timer_delete() is less work, and is basically just as likely to stop a
pointless call to flush_delayed_bios().

Fixes: 26b9f228703f ("dm: delay target")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
drivers/md/dm-delay.c

index 5eabdb06c6498b103f24e7316e3de2587f6bca45..eec0daa4b227a45049c48b69b21ac6507cdcadb6 100644 (file)
@@ -154,8 +154,10 @@ static void delay_dtr(struct dm_target *ti)
 {
        struct delay_c *dc = ti->private;
 
-       if (dc->kdelayd_wq)
+       if (dc->kdelayd_wq) {
+               timer_shutdown_sync(&dc->delay_timer);
                destroy_workqueue(dc->kdelayd_wq);
+       }
 
        if (dc->read.dev)
                dm_put_device(ti, dc->read.dev);
@@ -335,7 +337,7 @@ static void delay_presuspend(struct dm_target *ti)
        mutex_unlock(&delayed_bios_lock);
 
        if (!delay_is_fast(dc))
-               del_timer_sync(&dc->delay_timer);
+               timer_delete(&dc->delay_timer);
        flush_delayed_bios(dc, true);
 }