aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2013-04-15 16:55:41 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-04-29 15:41:48 -0400
commit1b1089561ce596a4032ba1039365090304db1cfd (patch)
tree5958e757c7d664ea874ab2b11bf231f8f5964cbd /drivers
parentc08c464d6f4136d9e48ffa23c0bcd93442343b2a (diff)
mISDN: fix races between misdn_del_timer() and timer callback
mark the victim with negative ->id if misdn_del_timer() finds it on the list, have timer callback *not* move ones so marked to dev->expired Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/isdn/mISDN/timerdev.c22
1 files changed, 9 insertions, 13 deletions
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c
index 5a1a5cadc766..c00546f830db 100644
--- a/drivers/isdn/mISDN/timerdev.c
+++ b/drivers/isdn/mISDN/timerdev.c
@@ -163,7 +163,8 @@ dev_expire_timer(unsigned long data)
163 u_long flags; 163 u_long flags;
164 164
165 spin_lock_irqsave(&timer->dev->lock, flags); 165 spin_lock_irqsave(&timer->dev->lock, flags);
166 list_move_tail(&timer->list, &timer->dev->expired); 166 if (timer->id >= 0)
167 list_move_tail(&timer->list, &timer->dev->expired);
167 spin_unlock_irqrestore(&timer->dev->lock, flags); 168 spin_unlock_irqrestore(&timer->dev->lock, flags);
168 wake_up_interruptible(&timer->dev->wait); 169 wake_up_interruptible(&timer->dev->wait);
169} 170}
@@ -203,26 +204,21 @@ misdn_add_timer(struct mISDNtimerdev *dev, int timeout)
203static int 204static int
204misdn_del_timer(struct mISDNtimerdev *dev, int id) 205misdn_del_timer(struct mISDNtimerdev *dev, int id)
205{ 206{
206 u_long flags;
207 struct mISDNtimer *timer; 207 struct mISDNtimer *timer;
208 int ret = 0;
209 208
210 spin_lock_irqsave(&dev->lock, flags); 209 spin_lock_irq(&dev->lock);
211 list_for_each_entry(timer, &dev->pending, list) { 210 list_for_each_entry(timer, &dev->pending, list) {
212 if (timer->id == id) { 211 if (timer->id == id) {
213 list_del_init(&timer->list); 212 list_del_init(&timer->list);
214 /* RED-PEN AK: race -- timer can be still running on 213 timer->id = -1;
215 * other CPU. Needs reference count I think 214 spin_unlock_irq(&dev->lock);
216 */ 215 del_timer_sync(&timer->tl);
217 del_timer(&timer->tl);
218 ret = timer->id;
219 kfree(timer); 216 kfree(timer);
220 goto unlock; 217 return id;
221 } 218 }
222 } 219 }
223unlock: 220 spin_unlock_irq(&dev->lock);
224 spin_unlock_irqrestore(&dev->lock, flags); 221 return 0;
225 return ret;
226} 222}
227 223
228static long 224static long