diff options
author | Davide Libenzi <davidel@xmailserver.org> | 2007-05-18 15:02:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-18 16:09:34 -0400 |
commit | 18963c01b8abf381f102752ce024c3582a716125 (patch) | |
tree | 6c7e594804608be82ec3988399e905e20d486f51 /fs/timerfd.c | |
parent | d48eb2331595224ffe89665e79721d44b40bb047 (diff) |
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>
Diffstat (limited to 'fs/timerfd.c')
-rw-r--r-- | fs/timerfd.c | 24 |
1 files changed, 11 insertions, 13 deletions
diff --git a/fs/timerfd.c b/fs/timerfd.c index e329e37f15a8..af9eca5c0230 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c | |||
@@ -24,7 +24,6 @@ | |||
24 | struct timerfd_ctx { | 24 | struct timerfd_ctx { |
25 | struct hrtimer tmr; | 25 | struct hrtimer tmr; |
26 | ktime_t tintv; | 26 | ktime_t tintv; |
27 | spinlock_t lock; | ||
28 | wait_queue_head_t wqh; | 27 | wait_queue_head_t wqh; |
29 | int expired; | 28 | int expired; |
30 | }; | 29 | }; |
@@ -39,10 +38,10 @@ static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr) | |||
39 | struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr); | 38 | struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr); |
40 | unsigned long flags; | 39 | unsigned long flags; |
41 | 40 | ||
42 | spin_lock_irqsave(&ctx->lock, flags); | 41 | spin_lock_irqsave(&ctx->wqh.lock, flags); |
43 | ctx->expired = 1; | 42 | ctx->expired = 1; |
44 | wake_up_locked(&ctx->wqh); | 43 | wake_up_locked(&ctx->wqh); |
45 | spin_unlock_irqrestore(&ctx->lock, flags); | 44 | spin_unlock_irqrestore(&ctx->wqh.lock, flags); |
46 | 45 | ||
47 | return HRTIMER_NORESTART; | 46 | return HRTIMER_NORESTART; |
48 | } | 47 | } |
@@ -83,10 +82,10 @@ static unsigned int timerfd_poll(struct file *file, poll_table *wait) | |||
83 | 82 | ||
84 | poll_wait(file, &ctx->wqh, wait); | 83 | poll_wait(file, &ctx->wqh, wait); |
85 | 84 | ||
86 | spin_lock_irqsave(&ctx->lock, flags); | 85 | spin_lock_irqsave(&ctx->wqh.lock, flags); |
87 | if (ctx->expired) | 86 | if (ctx->expired) |
88 | events |= POLLIN; | 87 | events |= POLLIN; |
89 | spin_unlock_irqrestore(&ctx->lock, flags); | 88 | spin_unlock_irqrestore(&ctx->wqh.lock, flags); |
90 | 89 | ||
91 | return events; | 90 | return events; |
92 | } | 91 | } |
@@ -101,7 +100,7 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count, | |||
101 | 100 | ||
102 | if (count < sizeof(ticks)) | 101 | if (count < sizeof(ticks)) |
103 | return -EINVAL; | 102 | return -EINVAL; |
104 | spin_lock_irq(&ctx->lock); | 103 | spin_lock_irq(&ctx->wqh.lock); |
105 | res = -EAGAIN; | 104 | res = -EAGAIN; |
106 | if (!ctx->expired && !(file->f_flags & O_NONBLOCK)) { | 105 | if (!ctx->expired && !(file->f_flags & O_NONBLOCK)) { |
107 | __add_wait_queue(&ctx->wqh, &wait); | 106 | __add_wait_queue(&ctx->wqh, &wait); |
@@ -115,9 +114,9 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count, | |||
115 | res = -ERESTARTSYS; | 114 | res = -ERESTARTSYS; |
116 | break; | 115 | break; |
117 | } | 116 | } |
118 | spin_unlock_irq(&ctx->lock); | 117 | spin_unlock_irq(&ctx->wqh.lock); |
119 | schedule(); | 118 | schedule(); |
120 | spin_lock_irq(&ctx->lock); | 119 | spin_lock_irq(&ctx->wqh.lock); |
121 | } | 120 | } |
122 | __remove_wait_queue(&ctx->wqh, &wait); | 121 | __remove_wait_queue(&ctx->wqh, &wait); |
123 | __set_current_state(TASK_RUNNING); | 122 | __set_current_state(TASK_RUNNING); |
@@ -139,7 +138,7 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count, | |||
139 | } else | 138 | } else |
140 | ticks = 1; | 139 | ticks = 1; |
141 | } | 140 | } |
142 | spin_unlock_irq(&ctx->lock); | 141 | spin_unlock_irq(&ctx->wqh.lock); |
143 | if (ticks) | 142 | if (ticks) |
144 | res = put_user(ticks, buf) ? -EFAULT: sizeof(ticks); | 143 | res = put_user(ticks, buf) ? -EFAULT: sizeof(ticks); |
145 | return res; | 144 | return res; |
@@ -176,7 +175,6 @@ asmlinkage long sys_timerfd(int ufd, int clockid, int flags, | |||
176 | return -ENOMEM; | 175 | return -ENOMEM; |
177 | 176 | ||
178 | init_waitqueue_head(&ctx->wqh); | 177 | init_waitqueue_head(&ctx->wqh); |
179 | spin_lock_init(&ctx->lock); | ||
180 | 178 | ||
181 | timerfd_setup(ctx, clockid, flags, &ktmr); | 179 | timerfd_setup(ctx, clockid, flags, &ktmr); |
182 | 180 | ||
@@ -202,10 +200,10 @@ asmlinkage long sys_timerfd(int ufd, int clockid, int flags, | |||
202 | * it to the new values. | 200 | * it to the new values. |
203 | */ | 201 | */ |
204 | for (;;) { | 202 | for (;;) { |
205 | spin_lock_irq(&ctx->lock); | 203 | spin_lock_irq(&ctx->wqh.lock); |
206 | if (hrtimer_try_to_cancel(&ctx->tmr) >= 0) | 204 | if (hrtimer_try_to_cancel(&ctx->tmr) >= 0) |
207 | break; | 205 | break; |
208 | spin_unlock_irq(&ctx->lock); | 206 | spin_unlock_irq(&ctx->wqh.lock); |
209 | cpu_relax(); | 207 | cpu_relax(); |
210 | } | 208 | } |
211 | /* | 209 | /* |
@@ -213,7 +211,7 @@ asmlinkage long sys_timerfd(int ufd, int clockid, int flags, | |||
213 | */ | 211 | */ |
214 | timerfd_setup(ctx, clockid, flags, &ktmr); | 212 | timerfd_setup(ctx, clockid, flags, &ktmr); |
215 | 213 | ||
216 | spin_unlock_irq(&ctx->lock); | 214 | spin_unlock_irq(&ctx->wqh.lock); |
217 | fput(file); | 215 | fput(file); |
218 | } | 216 | } |
219 | 217 | ||