]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - queue-5.10/comedi-comedi_test-prevent-timers-rescheduling-during-deletion.patch
5.10-stable patches
[thirdparty/kernel/stable-queue.git] / queue-5.10 / comedi-comedi_test-prevent-timers-rescheduling-during-deletion.patch
CommitLineData
627e3360
GKH
1From f53641a6e849034a44bf80f50245a75d7a376025 Mon Sep 17 00:00:00 2001
2From: Ian Abbott <abbotti@mev.co.uk>
3Date: Wed, 14 Feb 2024 10:07:25 +0000
4Subject: comedi: comedi_test: Prevent timers rescheduling during deletion
5
6From: Ian Abbott <abbotti@mev.co.uk>
7
8commit f53641a6e849034a44bf80f50245a75d7a376025 upstream.
9
10The comedi_test devices have a couple of timers (ai_timer and ao_timer)
11that can be started to simulate hardware interrupts. Their expiry
12functions normally reschedule the timer. The driver code calls either
13del_timer_sync() or del_timer() to delete the timers from the queue, but
14does not currently prevent the timers from rescheduling themselves so
15synchronized deletion may be ineffective.
16
17Add a couple of boolean members (one for each timer: ai_timer_enable and
18ao_timer_enable) to the device private data structure to indicate
19whether the timers are allowed to reschedule themselves. Set the member
20to true when adding the timer to the queue, and to false when deleting
21the timer from the queue in the waveform_ai_cancel() and
22waveform_ao_cancel() functions.
23
24The del_timer_sync() function is also called from the waveform_detach()
25function, but the timer enable members will already be set to false when
26that function is called, so no change is needed there.
27
28Fixes: 403fe7f34e33 ("staging: comedi: comedi_test: fix timer race conditions")
29Cc: stable@vger.kernel.org # 4.4+
30Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
31Link: https://lore.kernel.org/r/20240214100747.16203-1-abbotti@mev.co.uk
32Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
33---
34 drivers/staging/comedi/drivers/comedi_test.c | 30 +++++++++++++++++++++++----
35 1 file changed, 26 insertions(+), 4 deletions(-)
36
37--- a/drivers/staging/comedi/drivers/comedi_test.c
38+++ b/drivers/staging/comedi/drivers/comedi_test.c
39@@ -87,6 +87,8 @@ struct waveform_private {
40 struct comedi_device *dev; /* parent comedi device */
41 u64 ao_last_scan_time; /* time of previous AO scan in usec */
42 unsigned int ao_scan_period; /* AO scan period in usec */
43+ bool ai_timer_enable:1; /* should AI timer be running? */
44+ bool ao_timer_enable:1; /* should AO timer be running? */
45 unsigned short ao_loopbacks[N_CHANS];
46 };
47
48@@ -236,8 +238,12 @@ static void waveform_ai_timer(struct tim
49 time_increment = devpriv->ai_convert_time - now;
50 else
51 time_increment = 1;
52- mod_timer(&devpriv->ai_timer,
53- jiffies + usecs_to_jiffies(time_increment));
54+ spin_lock(&dev->spinlock);
55+ if (devpriv->ai_timer_enable) {
56+ mod_timer(&devpriv->ai_timer,
57+ jiffies + usecs_to_jiffies(time_increment));
58+ }
59+ spin_unlock(&dev->spinlock);
60 }
61
62 overrun:
63@@ -393,9 +399,12 @@ static int waveform_ai_cmd(struct comedi
64 * Seem to need an extra jiffy here, otherwise timer expires slightly
65 * early!
66 */
67+ spin_lock_bh(&dev->spinlock);
68+ devpriv->ai_timer_enable = true;
69 devpriv->ai_timer.expires =
70 jiffies + usecs_to_jiffies(devpriv->ai_convert_period) + 1;
71 add_timer(&devpriv->ai_timer);
72+ spin_unlock_bh(&dev->spinlock);
73 return 0;
74 }
75
76@@ -404,6 +413,9 @@ static int waveform_ai_cancel(struct com
77 {
78 struct waveform_private *devpriv = dev->private;
79
80+ spin_lock_bh(&dev->spinlock);
81+ devpriv->ai_timer_enable = false;
82+ spin_unlock_bh(&dev->spinlock);
83 if (in_softirq()) {
84 /* Assume we were called from the timer routine itself. */
85 del_timer(&devpriv->ai_timer);
86@@ -495,8 +507,12 @@ static void waveform_ao_timer(struct tim
87 unsigned int time_inc = devpriv->ao_last_scan_time +
88 devpriv->ao_scan_period - now;
89
90- mod_timer(&devpriv->ao_timer,
91- jiffies + usecs_to_jiffies(time_inc));
92+ spin_lock(&dev->spinlock);
93+ if (devpriv->ao_timer_enable) {
94+ mod_timer(&devpriv->ao_timer,
95+ jiffies + usecs_to_jiffies(time_inc));
96+ }
97+ spin_unlock(&dev->spinlock);
98 }
99
100 underrun:
101@@ -517,9 +533,12 @@ static int waveform_ao_inttrig_start(str
102 async->inttrig = NULL;
103
104 devpriv->ao_last_scan_time = ktime_to_us(ktime_get());
105+ spin_lock_bh(&dev->spinlock);
106+ devpriv->ao_timer_enable = true;
107 devpriv->ao_timer.expires =
108 jiffies + usecs_to_jiffies(devpriv->ao_scan_period);
109 add_timer(&devpriv->ao_timer);
110+ spin_unlock_bh(&dev->spinlock);
111
112 return 1;
113 }
114@@ -604,6 +623,9 @@ static int waveform_ao_cancel(struct com
115 struct waveform_private *devpriv = dev->private;
116
117 s->async->inttrig = NULL;
118+ spin_lock_bh(&dev->spinlock);
119+ devpriv->ao_timer_enable = false;
120+ spin_unlock_bh(&dev->spinlock);
121 if (in_softirq()) {
122 /* Assume we were called from the timer routine itself. */
123 del_timer(&devpriv->ao_timer);