fs/eventpoll.c

Source file repositories/reference/linux-study-clean/fs/eventpoll.c

File Facts

System
Linux kernel
Corpus path
fs/eventpoll.c
Extension
.c
Size
84115 bytes
Lines
3013
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: syscall or user/kernel boundary
Status
core implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

SYSCALL_DEFINE1(epoll_create1, int, flags)
{
	return do_epoll_create(flags);
}

SYSCALL_DEFINE1(epoll_create, int, size)
{
	if (size <= 0)
		return -EINVAL;

	return do_epoll_create(0);
}

#ifdef CONFIG_PM_SLEEP
static inline void ep_take_care_of_epollwakeup(struct epoll_event *epev)
{
	if ((epev->events & EPOLLWAKEUP) && !capable(CAP_BLOCK_SUSPEND))
		epev->events &= ~EPOLLWAKEUP;
}
#else
static inline void ep_take_care_of_epollwakeup(struct epoll_event *epev)
{
	epev->events &= ~EPOLLWAKEUP;
}
#endif

static inline int epoll_mutex_lock(struct mutex *mutex, bool nonblock)
{
	if (!nonblock) {
		mutex_lock(mutex);
		return 0;
	}
	return mutex_trylock(mutex) ? 0 : -EAGAIN;
}

/*
 * Acquire the locks required for do_epoll_ctl() on @ep for @op.
 *
 * Always takes ep->mtx. For EPOLL_CTL_ADD, additionally runs the
 * loop / path check under epnested_mutex when the topology can
 * change: @ep is already watched (epfile->f_ep non-NULL), @ep was
 * recently loop-checked (ep->gen == loop_check_gen), or @tfile is
 * itself an eventpoll.
 *
 * Return value encodes both outcome and lock state:
 *
 *   0        success; ep->mtx held.
 *   1        success; ep->mtx held AND the full check ran under
 *            epnested_mutex (which is also still held). The value
 *            doubles as the @full_check argument to ep_insert().
 *   -errno   failure; no locks held.
 *
 * The caller releases what was taken with ep_ctl_unlock(ep, ret).
 *
 * Holding epnested_mutex on add is what prevents two racing
 * EPOLL_CTL_ADDs on different eps from building a cycle without
 * either walker observing it.
 */
static int ep_ctl_lock(struct ep_ctl_ctx *ctx, struct eventpoll *ep, int op,
		       struct file *epfile, struct file *tfile, bool nonblock)
{
	struct eventpoll *tep;
	int error;

	error = epoll_mutex_lock(&ep->mtx, nonblock);
	if (error)
		return error;

	if (op != EPOLL_CTL_ADD)
		return 0;
	if (!READ_ONCE(epfile->f_ep) && ep->gen != loop_check_gen &&
	    !is_file_epoll(tfile))
		return 0;

	/* Full check needed: drop ep->mtx so we can take epnested_mutex. */
	mutex_unlock(&ep->mtx);
	error = epoll_mutex_lock(&epnested_mutex, nonblock);
	if (error)
		return error;

	loop_check_gen++;

	if (is_file_epoll(tfile)) {
		tep = tfile->private_data;
		if (ep_loop_check(ctx, ep, tep) != 0) {
			error = -ELOOP;
			goto err_unlock_nested;
		}
	}

Annotation

Implementation Notes