fs/timerfd.c

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

File Facts

System
Linux kernel
Corpus path
fs/timerfd.c
Extension
.c
Size
15009 bytes
Lines
622
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_DEFINE2(timerfd_create, int, clockid, int, flags)
{
	struct timerfd_ctx *ctx __free(kfree) = NULL;
	int ret;

	/* Check the TFD_* constants for consistency.  */
	BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC);
	BUILD_BUG_ON(TFD_NONBLOCK != O_NONBLOCK);

	if ((flags & ~TFD_CREATE_FLAGS) ||
	    (clockid != CLOCK_MONOTONIC &&
	     clockid != CLOCK_REALTIME &&
	     clockid != CLOCK_REALTIME_ALARM &&
	     clockid != CLOCK_BOOTTIME &&
	     clockid != CLOCK_BOOTTIME_ALARM))
		return -EINVAL;

	if ((clockid == CLOCK_REALTIME_ALARM ||
	     clockid == CLOCK_BOOTTIME_ALARM) &&
	    !capable(CAP_WAKE_ALARM))
		return -EPERM;

	ctx = kzalloc_obj(*ctx);
	if (!ctx)
		return -ENOMEM;

	init_waitqueue_head(&ctx->wqh);
	spin_lock_init(&ctx->cancel_lock);
	ctx->clockid = clockid;

	if (isalarm(ctx))
		alarm_init(&ctx->t.alarm,
			   ctx->clockid == CLOCK_REALTIME_ALARM ?
			   ALARM_REALTIME : ALARM_BOOTTIME,
			   timerfd_alarmproc);
	else
		hrtimer_setup(&ctx->t.tmr, timerfd_tmrproc, clockid, HRTIMER_MODE_ABS);

	ctx->moffs = ktime_mono_to_real(0);

	ret = FD_ADD(flags & TFD_SHARED_FCNTL_FLAGS,
		     anon_inode_getfile_fmode("[timerfd]", &timerfd_fops, ctx,
					      O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS),
					      FMODE_NOWAIT));
	if (ret >= 0)
		retain_and_null_ptr(ctx);
	return ret;
}

static int do_timerfd_settime(int ufd, int flags, 
		const struct itimerspec64 *new,
		struct itimerspec64 *old)
{
	struct timerfd_ctx *ctx;
	int ret;

	if ((flags & ~TFD_SETTIME_FLAGS) ||
		 !itimerspec64_valid(new))
		return -EINVAL;

	CLASS(fd, f)(ufd);
	if (fd_empty(f))
		return -EBADF;

	if (fd_file(f)->f_op != &timerfd_fops)
		return -EINVAL;

	ctx = fd_file(f)->private_data;

	if (isalarm(ctx) && !capable(CAP_WAKE_ALARM))
		return -EPERM;

	timerfd_setup_cancel(ctx, flags);

	/*
	 * We need to stop the existing timer before reprogramming
	 * it to the new values.
	 */
	for (;;) {
		spin_lock_irq(&ctx->wqh.lock);

		if (isalarm(ctx)) {
			if (alarm_try_to_cancel(&ctx->t.alarm) >= 0)
				break;
		} else {
			if (hrtimer_try_to_cancel(&ctx->t.tmr) >= 0)
				break;
		}
		spin_unlock_irq(&ctx->wqh.lock);

Annotation

Implementation Notes