Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b108956 authored by Al Viro's avatar Al Viro
Browse files

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent c08c464d
Loading
Loading
Loading
Loading
+9 −13
Original line number Diff line number Diff line
@@ -163,6 +163,7 @@ dev_expire_timer(unsigned long data)
	u_long			flags;

	spin_lock_irqsave(&timer->dev->lock, flags);
	if (timer->id >= 0)
		list_move_tail(&timer->list, &timer->dev->expired);
	spin_unlock_irqrestore(&timer->dev->lock, flags);
	wake_up_interruptible(&timer->dev->wait);
@@ -203,26 +204,21 @@ misdn_add_timer(struct mISDNtimerdev *dev, int timeout)
static int
misdn_del_timer(struct mISDNtimerdev *dev, int id)
{
	u_long			flags;
	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) {
		if (timer->id == id) {
			list_del_init(&timer->list);
			/* RED-PEN AK: race -- timer can be still running on
			 * other CPU. Needs reference count I think
			 */
			del_timer(&timer->tl);
			ret = timer->id;
			timer->id = -1;
			spin_unlock_irq(&dev->lock);
			del_timer_sync(&timer->tl);
			kfree(timer);
			goto unlock;
			return id;
		}
	}
unlock:
	spin_unlock_irqrestore(&dev->lock, flags);
	return ret;
	spin_unlock_irq(&dev->lock);
	return 0;
}

static long