timerfd use waitqueue lock ...

The timerfd was using the unlocked waitqueue operations, but it was
using a different lock, so poll_wait() would race with it.

This makes timerfd directly use the waitqueue lock.

Signed-off-by: Davide Libenzi <davidel@xmailserver.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Davide Libenzi 2007-05-18 12:02:33 -07:00 committed by Linus Torvalds
parent d48eb23315
commit 18963c01b8

View file

@ -24,7 +24,6 @@
struct timerfd_ctx { struct timerfd_ctx {
struct hrtimer tmr; struct hrtimer tmr;
ktime_t tintv; ktime_t tintv;
spinlock_t lock;
wait_queue_head_t wqh; wait_queue_head_t wqh;
int expired; int expired;
}; };
@ -39,10 +38,10 @@ static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr); struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ctx->lock, flags); spin_lock_irqsave(&ctx->wqh.lock, flags);
ctx->expired = 1; ctx->expired = 1;
wake_up_locked(&ctx->wqh); wake_up_locked(&ctx->wqh);
spin_unlock_irqrestore(&ctx->lock, flags); spin_unlock_irqrestore(&ctx->wqh.lock, flags);
return HRTIMER_NORESTART; return HRTIMER_NORESTART;
} }
@ -83,10 +82,10 @@ static unsigned int timerfd_poll(struct file *file, poll_table *wait)
poll_wait(file, &ctx->wqh, wait); poll_wait(file, &ctx->wqh, wait);
spin_lock_irqsave(&ctx->lock, flags); spin_lock_irqsave(&ctx->wqh.lock, flags);
if (ctx->expired) if (ctx->expired)
events |= POLLIN; events |= POLLIN;
spin_unlock_irqrestore(&ctx->lock, flags); spin_unlock_irqrestore(&ctx->wqh.lock, flags);
return events; return events;
} }
@ -101,7 +100,7 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
if (count < sizeof(ticks)) if (count < sizeof(ticks))
return -EINVAL; return -EINVAL;
spin_lock_irq(&ctx->lock); spin_lock_irq(&ctx->wqh.lock);
res = -EAGAIN; res = -EAGAIN;
if (!ctx->expired && !(file->f_flags & O_NONBLOCK)) { if (!ctx->expired && !(file->f_flags & O_NONBLOCK)) {
__add_wait_queue(&ctx->wqh, &wait); __add_wait_queue(&ctx->wqh, &wait);
@ -115,9 +114,9 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
res = -ERESTARTSYS; res = -ERESTARTSYS;
break; break;
} }
spin_unlock_irq(&ctx->lock); spin_unlock_irq(&ctx->wqh.lock);
schedule(); schedule();
spin_lock_irq(&ctx->lock); spin_lock_irq(&ctx->wqh.lock);
} }
__remove_wait_queue(&ctx->wqh, &wait); __remove_wait_queue(&ctx->wqh, &wait);
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
@ -139,7 +138,7 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
} else } else
ticks = 1; ticks = 1;
} }
spin_unlock_irq(&ctx->lock); spin_unlock_irq(&ctx->wqh.lock);
if (ticks) if (ticks)
res = put_user(ticks, buf) ? -EFAULT: sizeof(ticks); res = put_user(ticks, buf) ? -EFAULT: sizeof(ticks);
return res; return res;
@ -176,7 +175,6 @@ asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
return -ENOMEM; return -ENOMEM;
init_waitqueue_head(&ctx->wqh); init_waitqueue_head(&ctx->wqh);
spin_lock_init(&ctx->lock);
timerfd_setup(ctx, clockid, flags, &ktmr); timerfd_setup(ctx, clockid, flags, &ktmr);
@ -202,10 +200,10 @@ asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
* it to the new values. * it to the new values.
*/ */
for (;;) { for (;;) {
spin_lock_irq(&ctx->lock); spin_lock_irq(&ctx->wqh.lock);
if (hrtimer_try_to_cancel(&ctx->tmr) >= 0) if (hrtimer_try_to_cancel(&ctx->tmr) >= 0)
break; break;
spin_unlock_irq(&ctx->lock); spin_unlock_irq(&ctx->wqh.lock);
cpu_relax(); cpu_relax();
} }
/* /*
@ -213,7 +211,7 @@ asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
*/ */
timerfd_setup(ctx, clockid, flags, &ktmr); timerfd_setup(ctx, clockid, flags, &ktmr);
spin_unlock_irq(&ctx->lock); spin_unlock_irq(&ctx->wqh.lock);
fput(file); fput(file);
} }