diff options
Diffstat (limited to 'fs/eventfd.c')
-rw-r--r-- | fs/eventfd.c | 20 |
1 files changed, 11 insertions, 9 deletions
diff --git a/fs/eventfd.c b/fs/eventfd.c index 5de2c2db3aa2..91c0829a7035 100644 --- a/fs/eventfd.c +++ b/fs/eventfd.c | |||
@@ -28,6 +28,7 @@ struct eventfd_ctx { | |||
28 | * issue a wakeup. | 28 | * issue a wakeup. |
29 | */ | 29 | */ |
30 | __u64 count; | 30 | __u64 count; |
31 | unsigned int flags; | ||
31 | }; | 32 | }; |
32 | 33 | ||
33 | /* | 34 | /* |
@@ -87,22 +88,20 @@ static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count, | |||
87 | { | 88 | { |
88 | struct eventfd_ctx *ctx = file->private_data; | 89 | struct eventfd_ctx *ctx = file->private_data; |
89 | ssize_t res; | 90 | ssize_t res; |
90 | __u64 ucnt; | 91 | __u64 ucnt = 0; |
91 | DECLARE_WAITQUEUE(wait, current); | 92 | DECLARE_WAITQUEUE(wait, current); |
92 | 93 | ||
93 | if (count < sizeof(ucnt)) | 94 | if (count < sizeof(ucnt)) |
94 | return -EINVAL; | 95 | return -EINVAL; |
95 | spin_lock_irq(&ctx->wqh.lock); | 96 | spin_lock_irq(&ctx->wqh.lock); |
96 | res = -EAGAIN; | 97 | res = -EAGAIN; |
97 | ucnt = ctx->count; | 98 | if (ctx->count > 0) |
98 | if (ucnt > 0) | ||
99 | res = sizeof(ucnt); | 99 | res = sizeof(ucnt); |
100 | else if (!(file->f_flags & O_NONBLOCK)) { | 100 | else if (!(file->f_flags & O_NONBLOCK)) { |
101 | __add_wait_queue(&ctx->wqh, &wait); | 101 | __add_wait_queue(&ctx->wqh, &wait); |
102 | for (res = 0;;) { | 102 | for (res = 0;;) { |
103 | set_current_state(TASK_INTERRUPTIBLE); | 103 | set_current_state(TASK_INTERRUPTIBLE); |
104 | if (ctx->count > 0) { | 104 | if (ctx->count > 0) { |
105 | ucnt = ctx->count; | ||
106 | res = sizeof(ucnt); | 105 | res = sizeof(ucnt); |
107 | break; | 106 | break; |
108 | } | 107 | } |
@@ -117,8 +116,9 @@ static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count, | |||
117 | __remove_wait_queue(&ctx->wqh, &wait); | 116 | __remove_wait_queue(&ctx->wqh, &wait); |
118 | __set_current_state(TASK_RUNNING); | 117 | __set_current_state(TASK_RUNNING); |
119 | } | 118 | } |
120 | if (res > 0) { | 119 | if (likely(res > 0)) { |
121 | ctx->count = 0; | 120 | ucnt = (ctx->flags & EFD_SEMAPHORE) ? 1 : ctx->count; |
121 | ctx->count -= ucnt; | ||
122 | if (waitqueue_active(&ctx->wqh)) | 122 | if (waitqueue_active(&ctx->wqh)) |
123 | wake_up_locked(&ctx->wqh); | 123 | wake_up_locked(&ctx->wqh); |
124 | } | 124 | } |
@@ -166,7 +166,7 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t c | |||
166 | __remove_wait_queue(&ctx->wqh, &wait); | 166 | __remove_wait_queue(&ctx->wqh, &wait); |
167 | __set_current_state(TASK_RUNNING); | 167 | __set_current_state(TASK_RUNNING); |
168 | } | 168 | } |
169 | if (res > 0) { | 169 | if (likely(res > 0)) { |
170 | ctx->count += ucnt; | 170 | ctx->count += ucnt; |
171 | if (waitqueue_active(&ctx->wqh)) | 171 | if (waitqueue_active(&ctx->wqh)) |
172 | wake_up_locked(&ctx->wqh); | 172 | wake_up_locked(&ctx->wqh); |
@@ -207,7 +207,7 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) | |||
207 | BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC); | 207 | BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC); |
208 | BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK); | 208 | BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK); |
209 | 209 | ||
210 | if (flags & ~(EFD_CLOEXEC | EFD_NONBLOCK)) | 210 | if (flags & ~EFD_FLAGS_SET) |
211 | return -EINVAL; | 211 | return -EINVAL; |
212 | 212 | ||
213 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); | 213 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); |
@@ -216,13 +216,14 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) | |||
216 | 216 | ||
217 | init_waitqueue_head(&ctx->wqh); | 217 | init_waitqueue_head(&ctx->wqh); |
218 | ctx->count = count; | 218 | ctx->count = count; |
219 | ctx->flags = flags; | ||
219 | 220 | ||
220 | /* | 221 | /* |
221 | * When we call this, the initialization must be complete, since | 222 | * When we call this, the initialization must be complete, since |
222 | * anon_inode_getfd() will install the fd. | 223 | * anon_inode_getfd() will install the fd. |
223 | */ | 224 | */ |
224 | fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx, | 225 | fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx, |
225 | flags & (O_CLOEXEC | O_NONBLOCK)); | 226 | flags & EFD_SHARED_FCNTL_FLAGS); |
226 | if (fd < 0) | 227 | if (fd < 0) |
227 | kfree(ctx); | 228 | kfree(ctx); |
228 | return fd; | 229 | return fd; |
@@ -232,3 +233,4 @@ SYSCALL_DEFINE1(eventfd, unsigned int, count) | |||
232 | { | 233 | { |
233 | return sys_eventfd2(count, 0); | 234 | return sys_eventfd2(count, 0); |
234 | } | 235 | } |
236 | |||