mirror of
https://github.com/adulau/aha.git
synced 2024-12-29 04:06:22 +00:00
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:
parent
d48eb23315
commit
18963c01b8
1 changed files with 11 additions and 13 deletions
24
fs/timerfd.c
24
fs/timerfd.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue