162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  fs/eventfd.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/file.h>
1062306a36Sopenharmony_ci#include <linux/poll.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <linux/fs.h>
1362306a36Sopenharmony_ci#include <linux/sched/signal.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/list.h>
1762306a36Sopenharmony_ci#include <linux/spinlock.h>
1862306a36Sopenharmony_ci#include <linux/anon_inodes.h>
1962306a36Sopenharmony_ci#include <linux/syscalls.h>
2062306a36Sopenharmony_ci#include <linux/export.h>
2162306a36Sopenharmony_ci#include <linux/kref.h>
2262306a36Sopenharmony_ci#include <linux/eventfd.h>
2362306a36Sopenharmony_ci#include <linux/proc_fs.h>
2462306a36Sopenharmony_ci#include <linux/seq_file.h>
2562306a36Sopenharmony_ci#include <linux/idr.h>
2662306a36Sopenharmony_ci#include <linux/uio.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic DEFINE_IDA(eventfd_ida);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct eventfd_ctx {
3162306a36Sopenharmony_ci	struct kref kref;
3262306a36Sopenharmony_ci	wait_queue_head_t wqh;
3362306a36Sopenharmony_ci	/*
3462306a36Sopenharmony_ci	 * Every time that a write(2) is performed on an eventfd, the
3562306a36Sopenharmony_ci	 * value of the __u64 being written is added to "count" and a
3662306a36Sopenharmony_ci	 * wakeup is performed on "wqh". If EFD_SEMAPHORE flag was not
3762306a36Sopenharmony_ci	 * specified, a read(2) will return the "count" value to userspace,
3862306a36Sopenharmony_ci	 * and will reset "count" to zero. The kernel side eventfd_signal()
3962306a36Sopenharmony_ci	 * also, adds to the "count" counter and issue a wakeup.
4062306a36Sopenharmony_ci	 */
4162306a36Sopenharmony_ci	__u64 count;
4262306a36Sopenharmony_ci	unsigned int flags;
4362306a36Sopenharmony_ci	int id;
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci__u64 eventfd_signal_mask(struct eventfd_ctx *ctx, __u64 n, __poll_t mask)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	unsigned long flags;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	/*
5162306a36Sopenharmony_ci	 * Deadlock or stack overflow issues can happen if we recurse here
5262306a36Sopenharmony_ci	 * through waitqueue wakeup handlers. If the caller users potentially
5362306a36Sopenharmony_ci	 * nested waitqueues with custom wakeup handlers, then it should
5462306a36Sopenharmony_ci	 * check eventfd_signal_allowed() before calling this function. If
5562306a36Sopenharmony_ci	 * it returns false, the eventfd_signal() call should be deferred to a
5662306a36Sopenharmony_ci	 * safe context.
5762306a36Sopenharmony_ci	 */
5862306a36Sopenharmony_ci	if (WARN_ON_ONCE(current->in_eventfd))
5962306a36Sopenharmony_ci		return 0;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	spin_lock_irqsave(&ctx->wqh.lock, flags);
6262306a36Sopenharmony_ci	current->in_eventfd = 1;
6362306a36Sopenharmony_ci	if (ULLONG_MAX - ctx->count < n)
6462306a36Sopenharmony_ci		n = ULLONG_MAX - ctx->count;
6562306a36Sopenharmony_ci	ctx->count += n;
6662306a36Sopenharmony_ci	if (waitqueue_active(&ctx->wqh))
6762306a36Sopenharmony_ci		wake_up_locked_poll(&ctx->wqh, EPOLLIN | mask);
6862306a36Sopenharmony_ci	current->in_eventfd = 0;
6962306a36Sopenharmony_ci	spin_unlock_irqrestore(&ctx->wqh.lock, flags);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	return n;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/**
7562306a36Sopenharmony_ci * eventfd_signal - Adds @n to the eventfd counter.
7662306a36Sopenharmony_ci * @ctx: [in] Pointer to the eventfd context.
7762306a36Sopenharmony_ci * @n: [in] Value of the counter to be added to the eventfd internal counter.
7862306a36Sopenharmony_ci *          The value cannot be negative.
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci * This function is supposed to be called by the kernel in paths that do not
8162306a36Sopenharmony_ci * allow sleeping. In this function we allow the counter to reach the ULLONG_MAX
8262306a36Sopenharmony_ci * value, and we signal this as overflow condition by returning a EPOLLERR
8362306a36Sopenharmony_ci * to poll(2).
8462306a36Sopenharmony_ci *
8562306a36Sopenharmony_ci * Returns the amount by which the counter was incremented.  This will be less
8662306a36Sopenharmony_ci * than @n if the counter has overflowed.
8762306a36Sopenharmony_ci */
8862306a36Sopenharmony_ci__u64 eventfd_signal(struct eventfd_ctx *ctx, __u64 n)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	return eventfd_signal_mask(ctx, n, 0);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(eventfd_signal);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic void eventfd_free_ctx(struct eventfd_ctx *ctx)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	if (ctx->id >= 0)
9762306a36Sopenharmony_ci		ida_simple_remove(&eventfd_ida, ctx->id);
9862306a36Sopenharmony_ci	kfree(ctx);
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic void eventfd_free(struct kref *kref)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	struct eventfd_ctx *ctx = container_of(kref, struct eventfd_ctx, kref);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	eventfd_free_ctx(ctx);
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/**
10962306a36Sopenharmony_ci * eventfd_ctx_put - Releases a reference to the internal eventfd context.
11062306a36Sopenharmony_ci * @ctx: [in] Pointer to eventfd context.
11162306a36Sopenharmony_ci *
11262306a36Sopenharmony_ci * The eventfd context reference must have been previously acquired either
11362306a36Sopenharmony_ci * with eventfd_ctx_fdget() or eventfd_ctx_fileget().
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_civoid eventfd_ctx_put(struct eventfd_ctx *ctx)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	kref_put(&ctx->kref, eventfd_free);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(eventfd_ctx_put);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic int eventfd_release(struct inode *inode, struct file *file)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct eventfd_ctx *ctx = file->private_data;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	wake_up_poll(&ctx->wqh, EPOLLHUP);
12662306a36Sopenharmony_ci	eventfd_ctx_put(ctx);
12762306a36Sopenharmony_ci	return 0;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic __poll_t eventfd_poll(struct file *file, poll_table *wait)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	struct eventfd_ctx *ctx = file->private_data;
13362306a36Sopenharmony_ci	__poll_t events = 0;
13462306a36Sopenharmony_ci	u64 count;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	poll_wait(file, &ctx->wqh, wait);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/*
13962306a36Sopenharmony_ci	 * All writes to ctx->count occur within ctx->wqh.lock.  This read
14062306a36Sopenharmony_ci	 * can be done outside ctx->wqh.lock because we know that poll_wait
14162306a36Sopenharmony_ci	 * takes that lock (through add_wait_queue) if our caller will sleep.
14262306a36Sopenharmony_ci	 *
14362306a36Sopenharmony_ci	 * The read _can_ therefore seep into add_wait_queue's critical
14462306a36Sopenharmony_ci	 * section, but cannot move above it!  add_wait_queue's spin_lock acts
14562306a36Sopenharmony_ci	 * as an acquire barrier and ensures that the read be ordered properly
14662306a36Sopenharmony_ci	 * against the writes.  The following CAN happen and is safe:
14762306a36Sopenharmony_ci	 *
14862306a36Sopenharmony_ci	 *     poll                               write
14962306a36Sopenharmony_ci	 *     -----------------                  ------------
15062306a36Sopenharmony_ci	 *     lock ctx->wqh.lock (in poll_wait)
15162306a36Sopenharmony_ci	 *     count = ctx->count
15262306a36Sopenharmony_ci	 *     __add_wait_queue
15362306a36Sopenharmony_ci	 *     unlock ctx->wqh.lock
15462306a36Sopenharmony_ci	 *                                        lock ctx->qwh.lock
15562306a36Sopenharmony_ci	 *                                        ctx->count += n
15662306a36Sopenharmony_ci	 *                                        if (waitqueue_active)
15762306a36Sopenharmony_ci	 *                                          wake_up_locked_poll
15862306a36Sopenharmony_ci	 *                                        unlock ctx->qwh.lock
15962306a36Sopenharmony_ci	 *     eventfd_poll returns 0
16062306a36Sopenharmony_ci	 *
16162306a36Sopenharmony_ci	 * but the following, which would miss a wakeup, cannot happen:
16262306a36Sopenharmony_ci	 *
16362306a36Sopenharmony_ci	 *     poll                               write
16462306a36Sopenharmony_ci	 *     -----------------                  ------------
16562306a36Sopenharmony_ci	 *     count = ctx->count (INVALID!)
16662306a36Sopenharmony_ci	 *                                        lock ctx->qwh.lock
16762306a36Sopenharmony_ci	 *                                        ctx->count += n
16862306a36Sopenharmony_ci	 *                                        **waitqueue_active is false**
16962306a36Sopenharmony_ci	 *                                        **no wake_up_locked_poll!**
17062306a36Sopenharmony_ci	 *                                        unlock ctx->qwh.lock
17162306a36Sopenharmony_ci	 *     lock ctx->wqh.lock (in poll_wait)
17262306a36Sopenharmony_ci	 *     __add_wait_queue
17362306a36Sopenharmony_ci	 *     unlock ctx->wqh.lock
17462306a36Sopenharmony_ci	 *     eventfd_poll returns 0
17562306a36Sopenharmony_ci	 */
17662306a36Sopenharmony_ci	count = READ_ONCE(ctx->count);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	if (count > 0)
17962306a36Sopenharmony_ci		events |= EPOLLIN;
18062306a36Sopenharmony_ci	if (count == ULLONG_MAX)
18162306a36Sopenharmony_ci		events |= EPOLLERR;
18262306a36Sopenharmony_ci	if (ULLONG_MAX - 1 > count)
18362306a36Sopenharmony_ci		events |= EPOLLOUT;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	return events;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_civoid eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	lockdep_assert_held(&ctx->wqh.lock);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	*cnt = ((ctx->flags & EFD_SEMAPHORE) && ctx->count) ? 1 : ctx->count;
19362306a36Sopenharmony_ci	ctx->count -= *cnt;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(eventfd_ctx_do_read);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci/**
19862306a36Sopenharmony_ci * eventfd_ctx_remove_wait_queue - Read the current counter and removes wait queue.
19962306a36Sopenharmony_ci * @ctx: [in] Pointer to eventfd context.
20062306a36Sopenharmony_ci * @wait: [in] Wait queue to be removed.
20162306a36Sopenharmony_ci * @cnt: [out] Pointer to the 64-bit counter value.
20262306a36Sopenharmony_ci *
20362306a36Sopenharmony_ci * Returns %0 if successful, or the following error codes:
20462306a36Sopenharmony_ci *
20562306a36Sopenharmony_ci * -EAGAIN      : The operation would have blocked.
20662306a36Sopenharmony_ci *
20762306a36Sopenharmony_ci * This is used to atomically remove a wait queue entry from the eventfd wait
20862306a36Sopenharmony_ci * queue head, and read/reset the counter value.
20962306a36Sopenharmony_ci */
21062306a36Sopenharmony_ciint eventfd_ctx_remove_wait_queue(struct eventfd_ctx *ctx, wait_queue_entry_t *wait,
21162306a36Sopenharmony_ci				  __u64 *cnt)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	unsigned long flags;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	spin_lock_irqsave(&ctx->wqh.lock, flags);
21662306a36Sopenharmony_ci	eventfd_ctx_do_read(ctx, cnt);
21762306a36Sopenharmony_ci	__remove_wait_queue(&ctx->wqh, wait);
21862306a36Sopenharmony_ci	if (*cnt != 0 && waitqueue_active(&ctx->wqh))
21962306a36Sopenharmony_ci		wake_up_locked_poll(&ctx->wqh, EPOLLOUT);
22062306a36Sopenharmony_ci	spin_unlock_irqrestore(&ctx->wqh.lock, flags);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	return *cnt != 0 ? 0 : -EAGAIN;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(eventfd_ctx_remove_wait_queue);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic ssize_t eventfd_read(struct kiocb *iocb, struct iov_iter *to)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct file *file = iocb->ki_filp;
22962306a36Sopenharmony_ci	struct eventfd_ctx *ctx = file->private_data;
23062306a36Sopenharmony_ci	__u64 ucnt = 0;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (iov_iter_count(to) < sizeof(ucnt))
23362306a36Sopenharmony_ci		return -EINVAL;
23462306a36Sopenharmony_ci	spin_lock_irq(&ctx->wqh.lock);
23562306a36Sopenharmony_ci	if (!ctx->count) {
23662306a36Sopenharmony_ci		if ((file->f_flags & O_NONBLOCK) ||
23762306a36Sopenharmony_ci		    (iocb->ki_flags & IOCB_NOWAIT)) {
23862306a36Sopenharmony_ci			spin_unlock_irq(&ctx->wqh.lock);
23962306a36Sopenharmony_ci			return -EAGAIN;
24062306a36Sopenharmony_ci		}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci		if (wait_event_interruptible_locked_irq(ctx->wqh, ctx->count)) {
24362306a36Sopenharmony_ci			spin_unlock_irq(&ctx->wqh.lock);
24462306a36Sopenharmony_ci			return -ERESTARTSYS;
24562306a36Sopenharmony_ci		}
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci	eventfd_ctx_do_read(ctx, &ucnt);
24862306a36Sopenharmony_ci	current->in_eventfd = 1;
24962306a36Sopenharmony_ci	if (waitqueue_active(&ctx->wqh))
25062306a36Sopenharmony_ci		wake_up_locked_poll(&ctx->wqh, EPOLLOUT);
25162306a36Sopenharmony_ci	current->in_eventfd = 0;
25262306a36Sopenharmony_ci	spin_unlock_irq(&ctx->wqh.lock);
25362306a36Sopenharmony_ci	if (unlikely(copy_to_iter(&ucnt, sizeof(ucnt), to) != sizeof(ucnt)))
25462306a36Sopenharmony_ci		return -EFAULT;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	return sizeof(ucnt);
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count,
26062306a36Sopenharmony_ci			     loff_t *ppos)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct eventfd_ctx *ctx = file->private_data;
26362306a36Sopenharmony_ci	ssize_t res;
26462306a36Sopenharmony_ci	__u64 ucnt;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if (count < sizeof(ucnt))
26762306a36Sopenharmony_ci		return -EINVAL;
26862306a36Sopenharmony_ci	if (copy_from_user(&ucnt, buf, sizeof(ucnt)))
26962306a36Sopenharmony_ci		return -EFAULT;
27062306a36Sopenharmony_ci	if (ucnt == ULLONG_MAX)
27162306a36Sopenharmony_ci		return -EINVAL;
27262306a36Sopenharmony_ci	spin_lock_irq(&ctx->wqh.lock);
27362306a36Sopenharmony_ci	res = -EAGAIN;
27462306a36Sopenharmony_ci	if (ULLONG_MAX - ctx->count > ucnt)
27562306a36Sopenharmony_ci		res = sizeof(ucnt);
27662306a36Sopenharmony_ci	else if (!(file->f_flags & O_NONBLOCK)) {
27762306a36Sopenharmony_ci		res = wait_event_interruptible_locked_irq(ctx->wqh,
27862306a36Sopenharmony_ci				ULLONG_MAX - ctx->count > ucnt);
27962306a36Sopenharmony_ci		if (!res)
28062306a36Sopenharmony_ci			res = sizeof(ucnt);
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci	if (likely(res > 0)) {
28362306a36Sopenharmony_ci		ctx->count += ucnt;
28462306a36Sopenharmony_ci		current->in_eventfd = 1;
28562306a36Sopenharmony_ci		if (waitqueue_active(&ctx->wqh))
28662306a36Sopenharmony_ci			wake_up_locked_poll(&ctx->wqh, EPOLLIN);
28762306a36Sopenharmony_ci		current->in_eventfd = 0;
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci	spin_unlock_irq(&ctx->wqh.lock);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return res;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
29562306a36Sopenharmony_cistatic void eventfd_show_fdinfo(struct seq_file *m, struct file *f)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	struct eventfd_ctx *ctx = f->private_data;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	spin_lock_irq(&ctx->wqh.lock);
30062306a36Sopenharmony_ci	seq_printf(m, "eventfd-count: %16llx\n",
30162306a36Sopenharmony_ci		   (unsigned long long)ctx->count);
30262306a36Sopenharmony_ci	spin_unlock_irq(&ctx->wqh.lock);
30362306a36Sopenharmony_ci	seq_printf(m, "eventfd-id: %d\n", ctx->id);
30462306a36Sopenharmony_ci	seq_printf(m, "eventfd-semaphore: %d\n",
30562306a36Sopenharmony_ci		   !!(ctx->flags & EFD_SEMAPHORE));
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci#endif
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic const struct file_operations eventfd_fops = {
31062306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
31162306a36Sopenharmony_ci	.show_fdinfo	= eventfd_show_fdinfo,
31262306a36Sopenharmony_ci#endif
31362306a36Sopenharmony_ci	.release	= eventfd_release,
31462306a36Sopenharmony_ci	.poll		= eventfd_poll,
31562306a36Sopenharmony_ci	.read_iter	= eventfd_read,
31662306a36Sopenharmony_ci	.write		= eventfd_write,
31762306a36Sopenharmony_ci	.llseek		= noop_llseek,
31862306a36Sopenharmony_ci};
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci/**
32162306a36Sopenharmony_ci * eventfd_fget - Acquire a reference of an eventfd file descriptor.
32262306a36Sopenharmony_ci * @fd: [in] Eventfd file descriptor.
32362306a36Sopenharmony_ci *
32462306a36Sopenharmony_ci * Returns a pointer to the eventfd file structure in case of success, or the
32562306a36Sopenharmony_ci * following error pointer:
32662306a36Sopenharmony_ci *
32762306a36Sopenharmony_ci * -EBADF    : Invalid @fd file descriptor.
32862306a36Sopenharmony_ci * -EINVAL   : The @fd file descriptor is not an eventfd file.
32962306a36Sopenharmony_ci */
33062306a36Sopenharmony_cistruct file *eventfd_fget(int fd)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct file *file;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	file = fget(fd);
33562306a36Sopenharmony_ci	if (!file)
33662306a36Sopenharmony_ci		return ERR_PTR(-EBADF);
33762306a36Sopenharmony_ci	if (file->f_op != &eventfd_fops) {
33862306a36Sopenharmony_ci		fput(file);
33962306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	return file;
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(eventfd_fget);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/**
34762306a36Sopenharmony_ci * eventfd_ctx_fdget - Acquires a reference to the internal eventfd context.
34862306a36Sopenharmony_ci * @fd: [in] Eventfd file descriptor.
34962306a36Sopenharmony_ci *
35062306a36Sopenharmony_ci * Returns a pointer to the internal eventfd context, otherwise the error
35162306a36Sopenharmony_ci * pointers returned by the following functions:
35262306a36Sopenharmony_ci *
35362306a36Sopenharmony_ci * eventfd_fget
35462306a36Sopenharmony_ci */
35562306a36Sopenharmony_cistruct eventfd_ctx *eventfd_ctx_fdget(int fd)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct eventfd_ctx *ctx;
35862306a36Sopenharmony_ci	struct fd f = fdget(fd);
35962306a36Sopenharmony_ci	if (!f.file)
36062306a36Sopenharmony_ci		return ERR_PTR(-EBADF);
36162306a36Sopenharmony_ci	ctx = eventfd_ctx_fileget(f.file);
36262306a36Sopenharmony_ci	fdput(f);
36362306a36Sopenharmony_ci	return ctx;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(eventfd_ctx_fdget);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci/**
36862306a36Sopenharmony_ci * eventfd_ctx_fileget - Acquires a reference to the internal eventfd context.
36962306a36Sopenharmony_ci * @file: [in] Eventfd file pointer.
37062306a36Sopenharmony_ci *
37162306a36Sopenharmony_ci * Returns a pointer to the internal eventfd context, otherwise the error
37262306a36Sopenharmony_ci * pointer:
37362306a36Sopenharmony_ci *
37462306a36Sopenharmony_ci * -EINVAL   : The @fd file descriptor is not an eventfd file.
37562306a36Sopenharmony_ci */
37662306a36Sopenharmony_cistruct eventfd_ctx *eventfd_ctx_fileget(struct file *file)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	struct eventfd_ctx *ctx;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	if (file->f_op != &eventfd_fops)
38162306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	ctx = file->private_data;
38462306a36Sopenharmony_ci	kref_get(&ctx->kref);
38562306a36Sopenharmony_ci	return ctx;
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(eventfd_ctx_fileget);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic int do_eventfd(unsigned int count, int flags)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct eventfd_ctx *ctx;
39262306a36Sopenharmony_ci	struct file *file;
39362306a36Sopenharmony_ci	int fd;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	/* Check the EFD_* constants for consistency.  */
39662306a36Sopenharmony_ci	BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC);
39762306a36Sopenharmony_ci	BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	if (flags & ~EFD_FLAGS_SET)
40062306a36Sopenharmony_ci		return -EINVAL;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
40362306a36Sopenharmony_ci	if (!ctx)
40462306a36Sopenharmony_ci		return -ENOMEM;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	kref_init(&ctx->kref);
40762306a36Sopenharmony_ci	init_waitqueue_head(&ctx->wqh);
40862306a36Sopenharmony_ci	ctx->count = count;
40962306a36Sopenharmony_ci	ctx->flags = flags;
41062306a36Sopenharmony_ci	ctx->id = ida_simple_get(&eventfd_ida, 0, 0, GFP_KERNEL);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	flags &= EFD_SHARED_FCNTL_FLAGS;
41362306a36Sopenharmony_ci	flags |= O_RDWR;
41462306a36Sopenharmony_ci	fd = get_unused_fd_flags(flags);
41562306a36Sopenharmony_ci	if (fd < 0)
41662306a36Sopenharmony_ci		goto err;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	file = anon_inode_getfile("[eventfd]", &eventfd_fops, ctx, flags);
41962306a36Sopenharmony_ci	if (IS_ERR(file)) {
42062306a36Sopenharmony_ci		put_unused_fd(fd);
42162306a36Sopenharmony_ci		fd = PTR_ERR(file);
42262306a36Sopenharmony_ci		goto err;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	file->f_mode |= FMODE_NOWAIT;
42662306a36Sopenharmony_ci	fd_install(fd, file);
42762306a36Sopenharmony_ci	return fd;
42862306a36Sopenharmony_cierr:
42962306a36Sopenharmony_ci	eventfd_free_ctx(ctx);
43062306a36Sopenharmony_ci	return fd;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ciSYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	return do_eventfd(count, flags);
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ciSYSCALL_DEFINE1(eventfd, unsigned int, count)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	return do_eventfd(count, 0);
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
443