Procházet zdrojové kódy

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: Al Viro <viro@zeniv.linux.org.uk>
Al Viro před 12 roky
rodič
revize
1678ec00a6
1 změnil soubory, kde provedl 5 přidání a 9 odebrání
  1. 5 9
      drivers/isdn/mISDN/timerdev.c

+ 5 - 9
drivers/isdn/mISDN/timerdev.c

@@ -173,7 +173,6 @@ static int
 misdn_add_timer(struct mISDNtimerdev *dev, int timeout)
 {
 	int			id;
-	u_long			flags;
 	struct mISDNtimer	*timer;
 
 	if (!timeout) {
@@ -184,19 +183,16 @@ misdn_add_timer(struct mISDNtimerdev *dev, int timeout)
 		timer = kzalloc(sizeof(struct mISDNtimer), GFP_KERNEL);
 		if (!timer)
 			return -ENOMEM;
-		spin_lock_irqsave(&dev->lock, flags);
-		timer->id = dev->next_id++;
+		timer->dev = dev;
+		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)
 			dev->next_id = 1;
 		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);
 		add_timer(&timer->tl);
-		id = timer->id;
+		spin_unlock_irq(&dev->lock);
 	}
 	return id;
 }