Commit 1678ec00 authored by Al Viro's avatar Al Viro

mISDN: fix misdn_add_timer()/misdn_del_timer() race

do add_timer() *before* unlocking dev->lock, or unpleasant things can
happen if misdn_del_timer() on another CPU finds the sucker, calls
del_timer_sync() (which does nothing, since we hadn't started the
timer yet) and frees it, just as we get around to add_timer()...
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 1b108956
...@@ -173,7 +173,6 @@ static int ...@@ -173,7 +173,6 @@ static int
misdn_add_timer(struct mISDNtimerdev *dev, int timeout) misdn_add_timer(struct mISDNtimerdev *dev, int timeout)
{ {
int id; int id;
u_long flags;
struct mISDNtimer *timer; struct mISDNtimer *timer;
if (!timeout) { if (!timeout) {
...@@ -184,19 +183,16 @@ misdn_add_timer(struct mISDNtimerdev *dev, int timeout) ...@@ -184,19 +183,16 @@ misdn_add_timer(struct mISDNtimerdev *dev, int timeout)
timer = kzalloc(sizeof(struct mISDNtimer), GFP_KERNEL); timer = kzalloc(sizeof(struct mISDNtimer), GFP_KERNEL);
if (!timer) if (!timer)
return -ENOMEM; return -ENOMEM;
spin_lock_irqsave(&dev->lock, flags); timer->dev = dev;
timer->id = dev->next_id++; setup_timer(&timer->tl, dev_expire_timer, (long)timer);
spin_lock_irq(&dev->lock);
id = timer->id = dev->next_id++;
if (dev->next_id < 0) if (dev->next_id < 0)
dev->next_id = 1; dev->next_id = 1;
list_add_tail(&timer->list, &dev->pending); list_add_tail(&timer->list, &dev->pending);
spin_unlock_irqrestore(&dev->lock, flags);
timer->dev = dev;
timer->tl.data = (long)timer;
timer->tl.function = dev_expire_timer;
init_timer(&timer->tl);
timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000); timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000);
add_timer(&timer->tl); add_timer(&timer->tl);
id = timer->id; spin_unlock_irq(&dev->lock);
} }
return id; return id;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment