FAILED: patch "[PATCH] dm-delay: fix a race between delay_presuspend and delay_bio" failed to apply to 6.5-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.5-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.5.y
git checkout FETCH_HEAD
git cherry-pick -x 6fc45b6ed921dc00dfb264dc08c7d67ee63d2656
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2023112421-cathedral-speckled-9fa0@gregkh' --subject-prefix 'PATCH 6.5.y' HEAD^..
Possible dependencies:
6fc45b6ed921 ("dm-delay: fix a race between delay_presuspend and delay_bio") 70bbeb29fab0 ("dm delay: for short delays, use kthread instead of timers and wq")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 6fc45b6ed921dc00dfb264dc08c7d67ee63d2656 Mon Sep 17 00:00:00 2001
From: Mikulas Patocka <[email protected]>
Date: Fri, 17 Nov 2023 18:21:14 +0100
Subject: [PATCH] dm-delay: fix a race between delay_presuspend and delay_bio
In delay_presuspend, we set the atomic variable may_delay and then stop the timer and flush pending bios. The intention here is to prevent the delay target from re-arming the timer again.
However, this test is racy. Suppose that one thread goes to delay_bio, sees that dc->may_delay is one and proceeds; now, another thread executes delay_presuspend, it sets dc->may_delay to zero, deletes the timer and flushes pending bios. Then, the first thread continues and adds the bio to delayed->list despite the fact that dc->may_delay is false.
Fix this bug by changing may_delay's type from atomic_t to bool and only access it while holding the delayed_bios_lock mutex. Note that we don't have to grab the mutex in delay_resume because there are no bios in flight at this point.
drivers/md/dm-delay.c +11 -5
@@ -33,7 +33,7 @@ struct delay_c {struct work_struct flush_expired_bios;struct list_head delayed_bios;struct task_struct *worker; -atomic_t may_delay; +bool may_delay;struct delay_class read;struct delay_class write;
@@ -236,7 +236,7 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->private = dc;INIT_LIST_HEAD (&dc->delayed_bios); -atomic_set (&dc->may_delay,1 ); + dc->may_delay = true; dc->argc = argc; ret =delay_class_ctr (ti, &dc->read, argv);
@@ -312,7 +312,7 @@ static int delay_bio(struct delay_c *dc, struct delay_class *c, struct bio *bio)struct dm_delay_info *delayed;unsigned long expires =0 ; -if (!c->delay || !atomic_read (&dc->may_delay)) +if (!c->delay)return DM_MAPIO_REMAPPED ; delayed =dm_per_bio_data (bio,sizeof (struct dm_delay_info ));
@@ -321,6 +321,10 @@ static int delay_bio(struct delay_c *dc, struct delay_class *c, struct bio *bio) delayed->expires = expires = jiffies +msecs_to_jiffies (c->delay);mutex_lock (&delayed_bios_lock); +if (unlikely (!dc->may_delay)) { +mutex_unlock (&delayed_bios_lock); +return DM_MAPIO_REMAPPED ; + } c->ops++;list_add_tail (&delayed->list, &dc->delayed_bios);mutex_unlock (&delayed_bios_lock);
@@ -337,7 +341,9 @@ static void delay_presuspend(struct dm_target *ti) {struct delay_c *dc = ti->private; -atomic_set (&dc->may_delay,0 ); +mutex_lock (&delayed_bios_lock); + dc->may_delay = false; +mutex_unlock (&delayed_bios_lock);if (delay_is_fast (dc))flush_delayed_bios_fast (dc, true);
@@ -351,7 +357,7 @@ static void delay_resume(struct dm_target *ti) {struct delay_c *dc = ti->private; -atomic_set (&dc->may_delay,1 ); + dc->may_delay = true; }static int delay_map (struct dm_target *ti,struct bio *bio)