summaryrefslogtreecommitdiffstats
path: root/fs/eventfd.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-01-31 12:25:20 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2018-01-31 12:25:20 -0500
commit19e7b5f99474107e8d0b4b3e4652fa19ddb87efc (patch)
tree49f15b76c07b4c90d6fbd17b49d69017c81a4b58 /fs/eventfd.c
parent26064ea409b4d4acb05903a36f3fe2fdccb3d8aa (diff)
parentce4c253573ad184603e0fa77876ba155b0cde46d (diff)
Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull misc vfs updates from Al Viro: "All kinds of misc stuff, without any unifying topic, from various people. Neil's d_anon patch, several bugfixes, introduction of kvmalloc analogue of kmemdup_user(), extending bitfield.h to deal with fixed-endians, assorted cleanups all over the place..." * 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (28 commits) alpha: osf_sys.c: use timespec64 where appropriate alpha: osf_sys.c: fix put_tv32 regression jffs2: Fix use-after-free bug in jffs2_iget()'s error handling path dcache: delete unused d_hash_mask dcache: subtract d_hash_shift from 32 in advance fs/buffer.c: fold init_buffer() into init_page_buffers() fs: fold __inode_permission() into inode_permission() fs: add RWF_APPEND sctp: use vmemdup_user() rather than badly open-coding memdup_user() snd_ctl_elem_init_enum_names(): switch to vmemdup_user() replace_user_tlv(): switch to vmemdup_user() new primitive: vmemdup_user() memdup_user(): switch to GFP_USER eventfd: fold eventfd_ctx_get() into eventfd_ctx_fileget() eventfd: fold eventfd_ctx_read() into eventfd_read() eventfd: convert to use anon_inode_getfd() nfs4file: get rid of pointless include of btrfs.h uvc_v4l2: clean copyin/copyout up vme_user: don't use __copy_..._user() usx2y: don't bother with memdup_user() for 16-byte structure ...
Diffstat (limited to 'fs/eventfd.c')
-rw-r--r--fs/eventfd.c127
1 files changed, 28 insertions, 99 deletions
diff --git a/fs/eventfd.c b/fs/eventfd.c
index 6318a9b57e53..04fd824142a1 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -80,24 +80,11 @@ static void eventfd_free(struct kref *kref)
80} 80}
81 81
82/** 82/**
83 * eventfd_ctx_get - Acquires a reference to the internal eventfd context.
84 * @ctx: [in] Pointer to the eventfd context.
85 *
86 * Returns: In case of success, returns a pointer to the eventfd context.
87 */
88struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx)
89{
90 kref_get(&ctx->kref);
91 return ctx;
92}
93EXPORT_SYMBOL_GPL(eventfd_ctx_get);
94
95/**
96 * eventfd_ctx_put - Releases a reference to the internal eventfd context. 83 * eventfd_ctx_put - Releases a reference to the internal eventfd context.
97 * @ctx: [in] Pointer to eventfd context. 84 * @ctx: [in] Pointer to eventfd context.
98 * 85 *
99 * The eventfd context reference must have been previously acquired either 86 * The eventfd context reference must have been previously acquired either
100 * with eventfd_ctx_get() or eventfd_ctx_fdget(). 87 * with eventfd_ctx_fdget() or eventfd_ctx_fileget().
101 */ 88 */
102void eventfd_ctx_put(struct eventfd_ctx *ctx) 89void eventfd_ctx_put(struct eventfd_ctx *ctx)
103{ 90{
@@ -207,36 +194,27 @@ int eventfd_ctx_remove_wait_queue(struct eventfd_ctx *ctx, wait_queue_entry_t *w
207} 194}
208EXPORT_SYMBOL_GPL(eventfd_ctx_remove_wait_queue); 195EXPORT_SYMBOL_GPL(eventfd_ctx_remove_wait_queue);
209 196
210/** 197static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
211 * eventfd_ctx_read - Reads the eventfd counter or wait if it is zero. 198 loff_t *ppos)
212 * @ctx: [in] Pointer to eventfd context.
213 * @no_wait: [in] Different from zero if the operation should not block.
214 * @cnt: [out] Pointer to the 64-bit counter value.
215 *
216 * Returns %0 if successful, or the following error codes:
217 *
218 * - -EAGAIN : The operation would have blocked but @no_wait was non-zero.
219 * - -ERESTARTSYS : A signal interrupted the wait operation.
220 *
221 * If @no_wait is zero, the function might sleep until the eventfd internal
222 * counter becomes greater than zero.
223 */
224ssize_t eventfd_ctx_read(struct eventfd_ctx *ctx, int no_wait, __u64 *cnt)
225{ 199{
200 struct eventfd_ctx *ctx = file->private_data;
226 ssize_t res; 201 ssize_t res;
202 __u64 ucnt = 0;
227 DECLARE_WAITQUEUE(wait, current); 203 DECLARE_WAITQUEUE(wait, current);
228 204
205 if (count < sizeof(ucnt))
206 return -EINVAL;
207
229 spin_lock_irq(&ctx->wqh.lock); 208 spin_lock_irq(&ctx->wqh.lock);
230 *cnt = 0;
231 res = -EAGAIN; 209 res = -EAGAIN;
232 if (ctx->count > 0) 210 if (ctx->count > 0)
233 res = 0; 211 res = sizeof(ucnt);
234 else if (!no_wait) { 212 else if (!(file->f_flags & O_NONBLOCK)) {
235 __add_wait_queue(&ctx->wqh, &wait); 213 __add_wait_queue(&ctx->wqh, &wait);
236 for (;;) { 214 for (;;) {
237 set_current_state(TASK_INTERRUPTIBLE); 215 set_current_state(TASK_INTERRUPTIBLE);
238 if (ctx->count > 0) { 216 if (ctx->count > 0) {
239 res = 0; 217 res = sizeof(ucnt);
240 break; 218 break;
241 } 219 }
242 if (signal_pending(current)) { 220 if (signal_pending(current)) {
@@ -250,31 +228,17 @@ ssize_t eventfd_ctx_read(struct eventfd_ctx *ctx, int no_wait, __u64 *cnt)
250 __remove_wait_queue(&ctx->wqh, &wait); 228 __remove_wait_queue(&ctx->wqh, &wait);
251 __set_current_state(TASK_RUNNING); 229 __set_current_state(TASK_RUNNING);
252 } 230 }
253 if (likely(res == 0)) { 231 if (likely(res > 0)) {
254 eventfd_ctx_do_read(ctx, cnt); 232 eventfd_ctx_do_read(ctx, &ucnt);
255 if (waitqueue_active(&ctx->wqh)) 233 if (waitqueue_active(&ctx->wqh))
256 wake_up_locked_poll(&ctx->wqh, POLLOUT); 234 wake_up_locked_poll(&ctx->wqh, POLLOUT);
257 } 235 }
258 spin_unlock_irq(&ctx->wqh.lock); 236 spin_unlock_irq(&ctx->wqh.lock);
259 237
260 return res; 238 if (res > 0 && put_user(ucnt, (__u64 __user *)buf))
261} 239 return -EFAULT;
262EXPORT_SYMBOL_GPL(eventfd_ctx_read);
263
264static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
265 loff_t *ppos)
266{
267 struct eventfd_ctx *ctx = file->private_data;
268 ssize_t res;
269 __u64 cnt;
270
271 if (count < sizeof(cnt))
272 return -EINVAL;
273 res = eventfd_ctx_read(ctx, file->f_flags & O_NONBLOCK, &cnt);
274 if (res < 0)
275 return res;
276 240
277 return put_user(cnt, (__u64 __user *) buf) ? -EFAULT : sizeof(cnt); 241 return res;
278} 242}
279 243
280static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count, 244static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count,
@@ -405,79 +369,44 @@ EXPORT_SYMBOL_GPL(eventfd_ctx_fdget);
405 */ 369 */
406struct eventfd_ctx *eventfd_ctx_fileget(struct file *file) 370struct eventfd_ctx *eventfd_ctx_fileget(struct file *file)
407{ 371{
372 struct eventfd_ctx *ctx;
373
408 if (file->f_op != &eventfd_fops) 374 if (file->f_op != &eventfd_fops)
409 return ERR_PTR(-EINVAL); 375 return ERR_PTR(-EINVAL);
410 376
411 return eventfd_ctx_get(file->private_data); 377 ctx = file->private_data;
378 kref_get(&ctx->kref);
379 return ctx;
412} 380}
413EXPORT_SYMBOL_GPL(eventfd_ctx_fileget); 381EXPORT_SYMBOL_GPL(eventfd_ctx_fileget);
414 382
415/** 383SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
416 * eventfd_file_create - Creates an eventfd file pointer.
417 * @count: Initial eventfd counter value.
418 * @flags: Flags for the eventfd file.
419 *
420 * This function creates an eventfd file pointer, w/out installing it into
421 * the fd table. This is useful when the eventfd file is used during the
422 * initialization of data structures that require extra setup after the eventfd
423 * creation. So the eventfd creation is split into the file pointer creation
424 * phase, and the file descriptor installation phase.
425 * In this way races with userspace closing the newly installed file descriptor
426 * can be avoided.
427 * Returns an eventfd file pointer, or a proper error pointer.
428 */
429struct file *eventfd_file_create(unsigned int count, int flags)
430{ 384{
431 struct file *file;
432 struct eventfd_ctx *ctx; 385 struct eventfd_ctx *ctx;
386 int fd;
433 387
434 /* Check the EFD_* constants for consistency. */ 388 /* Check the EFD_* constants for consistency. */
435 BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC); 389 BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC);
436 BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK); 390 BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK);
437 391
438 if (flags & ~EFD_FLAGS_SET) 392 if (flags & ~EFD_FLAGS_SET)
439 return ERR_PTR(-EINVAL); 393 return -EINVAL;
440 394
441 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); 395 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
442 if (!ctx) 396 if (!ctx)
443 return ERR_PTR(-ENOMEM); 397 return -ENOMEM;
444 398
445 kref_init(&ctx->kref); 399 kref_init(&ctx->kref);
446 init_waitqueue_head(&ctx->wqh); 400 init_waitqueue_head(&ctx->wqh);
447 ctx->count = count; 401 ctx->count = count;
448 ctx->flags = flags; 402 ctx->flags = flags;
449 403
450 file = anon_inode_getfile("[eventfd]", &eventfd_fops, ctx, 404 fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx,
451 O_RDWR | (flags & EFD_SHARED_FCNTL_FLAGS)); 405 O_RDWR | (flags & EFD_SHARED_FCNTL_FLAGS));
452 if (IS_ERR(file)) 406 if (fd < 0)
453 eventfd_free_ctx(ctx); 407 eventfd_free_ctx(ctx);
454 408
455 return file;
456}
457
458SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
459{
460 int fd, error;
461 struct file *file;
462
463 error = get_unused_fd_flags(flags & EFD_SHARED_FCNTL_FLAGS);
464 if (error < 0)
465 return error;
466 fd = error;
467
468 file = eventfd_file_create(count, flags);
469 if (IS_ERR(file)) {
470 error = PTR_ERR(file);
471 goto err_put_unused_fd;
472 }
473 fd_install(fd, file);
474
475 return fd; 409 return fd;
476
477err_put_unused_fd:
478 put_unused_fd(fd);
479
480 return error;
481} 410}
482 411
483SYSCALL_DEFINE1(eventfd, unsigned int, count) 412SYSCALL_DEFINE1(eventfd, unsigned int, count)