Skip to content

Commit

Permalink
timerfd use waitqueue lock ...
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Davide Libenzi authored and Linus Torvalds committed May 18, 2007
1 parent d48eb23 commit 18963c0
Showing 1 changed file with 11 additions and 13 deletions.
24 changes: 11 additions & 13 deletions fs/timerfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
struct timerfd_ctx {
struct hrtimer tmr;
ktime_t tintv;
spinlock_t lock;
wait_queue_head_t wqh;
int expired;
};
Expand All @@ -39,10 +38,10 @@ static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
unsigned long flags;

spin_lock_irqsave(&ctx->lock, flags);
spin_lock_irqsave(&ctx->wqh.lock, flags);
ctx->expired = 1;
wake_up_locked(&ctx->wqh);
spin_unlock_irqrestore(&ctx->lock, flags);
spin_unlock_irqrestore(&ctx->wqh.lock, flags);

return HRTIMER_NORESTART;
}
Expand Down Expand Up @@ -83,10 +82,10 @@ static unsigned int timerfd_poll(struct file *file, poll_table *wait)

poll_wait(file, &ctx->wqh, wait);

spin_lock_irqsave(&ctx->lock, flags);
spin_lock_irqsave(&ctx->wqh.lock, flags);
if (ctx->expired)
events |= POLLIN;
spin_unlock_irqrestore(&ctx->lock, flags);
spin_unlock_irqrestore(&ctx->wqh.lock, flags);

return events;
}
Expand All @@ -101,7 +100,7 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,

if (count < sizeof(ticks))
return -EINVAL;
spin_lock_irq(&ctx->lock);
spin_lock_irq(&ctx->wqh.lock);
res = -EAGAIN;
if (!ctx->expired && !(file->f_flags & O_NONBLOCK)) {
__add_wait_queue(&ctx->wqh, &wait);
Expand All @@ -115,9 +114,9 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
res = -ERESTARTSYS;
break;
}
spin_unlock_irq(&ctx->lock);
spin_unlock_irq(&ctx->wqh.lock);
schedule();
spin_lock_irq(&ctx->lock);
spin_lock_irq(&ctx->wqh.lock);
}
__remove_wait_queue(&ctx->wqh, &wait);
__set_current_state(TASK_RUNNING);
Expand All @@ -139,7 +138,7 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
} else
ticks = 1;
}
spin_unlock_irq(&ctx->lock);
spin_unlock_irq(&ctx->wqh.lock);
if (ticks)
res = put_user(ticks, buf) ? -EFAULT: sizeof(ticks);
return res;
Expand Down Expand Up @@ -176,7 +175,6 @@ asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
return -ENOMEM;

init_waitqueue_head(&ctx->wqh);
spin_lock_init(&ctx->lock);

timerfd_setup(ctx, clockid, flags, &ktmr);

Expand All @@ -202,18 +200,18 @@ asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
* it to the new values.
*/
for (;;) {
spin_lock_irq(&ctx->lock);
spin_lock_irq(&ctx->wqh.lock);
if (hrtimer_try_to_cancel(&ctx->tmr) >= 0)
break;
spin_unlock_irq(&ctx->lock);
spin_unlock_irq(&ctx->wqh.lock);
cpu_relax();
}
/*
* Re-program the timer to the new value ...
*/
timerfd_setup(ctx, clockid, flags, &ktmr);

spin_unlock_irq(&ctx->lock);
spin_unlock_irq(&ctx->wqh.lock);
fput(file);
}

Expand Down

0 comments on commit 18963c0

Please sign in to comment.