diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2013-04-15 17:04:04 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-04-29 15:41:48 -0400 |
commit | 1678ec00a632f8b9204e28e5c506128881171604 (patch) | |
tree | 2e693539d928e501e91ddfedf90ea780e9e2bea2 | |
parent | 1b1089561ce596a4032ba1039365090304db1cfd (diff) |
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>
-rw-r--r-- | drivers/isdn/mISDN/timerdev.c | 14 |
1 files changed, 5 insertions, 9 deletions
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index c00546f830db..ddb8adcd5fbb 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c | |||
@@ -173,7 +173,6 @@ static int | |||
173 | misdn_add_timer(struct mISDNtimerdev *dev, int timeout) | 173 | misdn_add_timer(struct mISDNtimerdev *dev, int timeout) |
174 | { | 174 | { |
175 | int id; | 175 | int id; |
176 | u_long flags; | ||
177 | struct mISDNtimer *timer; | 176 | struct mISDNtimer *timer; |
178 | 177 | ||
179 | if (!timeout) { | 178 | if (!timeout) { |
@@ -184,19 +183,16 @@ misdn_add_timer(struct mISDNtimerdev *dev, int timeout) | |||
184 | timer = kzalloc(sizeof(struct mISDNtimer), GFP_KERNEL); | 183 | timer = kzalloc(sizeof(struct mISDNtimer), GFP_KERNEL); |
185 | if (!timer) | 184 | if (!timer) |
186 | return -ENOMEM; | 185 | return -ENOMEM; |
187 | spin_lock_irqsave(&dev->lock, flags); | 186 | timer->dev = dev; |
188 | timer->id = dev->next_id++; | 187 | setup_timer(&timer->tl, dev_expire_timer, (long)timer); |
188 | spin_lock_irq(&dev->lock); | ||
189 | id = timer->id = dev->next_id++; | ||
189 | if (dev->next_id < 0) | 190 | if (dev->next_id < 0) |
190 | dev->next_id = 1; | 191 | dev->next_id = 1; |
191 | list_add_tail(&timer->list, &dev->pending); | 192 | list_add_tail(&timer->list, &dev->pending); |
192 | spin_unlock_irqrestore(&dev->lock, flags); | ||
193 | timer->dev = dev; | ||
194 | timer->tl.data = (long)timer; | ||
195 | timer->tl.function = dev_expire_timer; | ||
196 | init_timer(&timer->tl); | ||
197 | timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000); | 193 | timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000); |
198 | add_timer(&timer->tl); | 194 | add_timer(&timer->tl); |
199 | id = timer->id; | 195 | spin_unlock_irq(&dev->lock); |
200 | } | 196 | } |
201 | return id; | 197 | return id; |
202 | } | 198 | } |