mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
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>
This commit is contained in:
parent
c08c464d6f
commit
1b1089561c
1 changed files with 9 additions and 13 deletions
|
@ -163,6 +163,7 @@ dev_expire_timer(unsigned long data)
|
||||||
u_long flags;
|
u_long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&timer->dev->lock, flags);
|
spin_lock_irqsave(&timer->dev->lock, flags);
|
||||||
|
if (timer->id >= 0)
|
||||||
list_move_tail(&timer->list, &timer->dev->expired);
|
list_move_tail(&timer->list, &timer->dev->expired);
|
||||||
spin_unlock_irqrestore(&timer->dev->lock, flags);
|
spin_unlock_irqrestore(&timer->dev->lock, flags);
|
||||||
wake_up_interruptible(&timer->dev->wait);
|
wake_up_interruptible(&timer->dev->wait);
|
||||||
|
@ -203,26 +204,21 @@ misdn_add_timer(struct mISDNtimerdev *dev, int timeout)
|
||||||
static int
|
static int
|
||||||
misdn_del_timer(struct mISDNtimerdev *dev, int id)
|
misdn_del_timer(struct mISDNtimerdev *dev, int id)
|
||||||
{
|
{
|
||||||
u_long flags;
|
|
||||||
struct mISDNtimer *timer;
|
struct mISDNtimer *timer;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->lock, flags);
|
spin_lock_irq(&dev->lock);
|
||||||
list_for_each_entry(timer, &dev->pending, list) {
|
list_for_each_entry(timer, &dev->pending, list) {
|
||||||
if (timer->id == id) {
|
if (timer->id == id) {
|
||||||
list_del_init(&timer->list);
|
list_del_init(&timer->list);
|
||||||
/* RED-PEN AK: race -- timer can be still running on
|
timer->id = -1;
|
||||||
* other CPU. Needs reference count I think
|
spin_unlock_irq(&dev->lock);
|
||||||
*/
|
del_timer_sync(&timer->tl);
|
||||||
del_timer(&timer->tl);
|
|
||||||
ret = timer->id;
|
|
||||||
kfree(timer);
|
kfree(timer);
|
||||||
goto unlock;
|
return id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unlock:
|
spin_unlock_irq(&dev->lock);
|
||||||
spin_unlock_irqrestore(&dev->lock, flags);
|
return 0;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long
|
static long
|
||||||
|
|
Loading…
Reference in a new issue