162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  fs/timerfd.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  Thanks to Thomas Gleixner for code reviews and useful comments.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/alarmtimer.h>
1362306a36Sopenharmony_ci#include <linux/file.h>
1462306a36Sopenharmony_ci#include <linux/poll.h>
1562306a36Sopenharmony_ci#include <linux/init.h>
1662306a36Sopenharmony_ci#include <linux/fs.h>
1762306a36Sopenharmony_ci#include <linux/sched.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/slab.h>
2062306a36Sopenharmony_ci#include <linux/list.h>
2162306a36Sopenharmony_ci#include <linux/spinlock.h>
2262306a36Sopenharmony_ci#include <linux/time.h>
2362306a36Sopenharmony_ci#include <linux/hrtimer.h>
2462306a36Sopenharmony_ci#include <linux/anon_inodes.h>
2562306a36Sopenharmony_ci#include <linux/timerfd.h>
2662306a36Sopenharmony_ci#include <linux/syscalls.h>
2762306a36Sopenharmony_ci#include <linux/compat.h>
2862306a36Sopenharmony_ci#include <linux/rcupdate.h>
2962306a36Sopenharmony_ci#include <linux/time_namespace.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct timerfd_ctx {
3262306a36Sopenharmony_ci	union {
3362306a36Sopenharmony_ci		struct hrtimer tmr;
3462306a36Sopenharmony_ci		struct alarm alarm;
3562306a36Sopenharmony_ci	} t;
3662306a36Sopenharmony_ci	ktime_t tintv;
3762306a36Sopenharmony_ci	ktime_t moffs;
3862306a36Sopenharmony_ci	wait_queue_head_t wqh;
3962306a36Sopenharmony_ci	u64 ticks;
4062306a36Sopenharmony_ci	int clockid;
4162306a36Sopenharmony_ci	short unsigned expired;
4262306a36Sopenharmony_ci	short unsigned settime_flags;	/* to show in fdinfo */
4362306a36Sopenharmony_ci	struct rcu_head rcu;
4462306a36Sopenharmony_ci	struct list_head clist;
4562306a36Sopenharmony_ci	spinlock_t cancel_lock;
4662306a36Sopenharmony_ci	bool might_cancel;
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic LIST_HEAD(cancel_list);
5062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(cancel_lock);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic inline bool isalarm(struct timerfd_ctx *ctx)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	return ctx->clockid == CLOCK_REALTIME_ALARM ||
5562306a36Sopenharmony_ci		ctx->clockid == CLOCK_BOOTTIME_ALARM;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/*
5962306a36Sopenharmony_ci * This gets called when the timer event triggers. We set the "expired"
6062306a36Sopenharmony_ci * flag, but we do not re-arm the timer (in case it's necessary,
6162306a36Sopenharmony_ci * tintv != 0) until the timer is accessed.
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_cistatic void timerfd_triggered(struct timerfd_ctx *ctx)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	unsigned long flags;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	spin_lock_irqsave(&ctx->wqh.lock, flags);
6862306a36Sopenharmony_ci	ctx->expired = 1;
6962306a36Sopenharmony_ci	ctx->ticks++;
7062306a36Sopenharmony_ci	wake_up_locked_poll(&ctx->wqh, EPOLLIN);
7162306a36Sopenharmony_ci	spin_unlock_irqrestore(&ctx->wqh.lock, flags);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx,
7762306a36Sopenharmony_ci					       t.tmr);
7862306a36Sopenharmony_ci	timerfd_triggered(ctx);
7962306a36Sopenharmony_ci	return HRTIMER_NORESTART;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic enum alarmtimer_restart timerfd_alarmproc(struct alarm *alarm,
8362306a36Sopenharmony_ci	ktime_t now)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct timerfd_ctx *ctx = container_of(alarm, struct timerfd_ctx,
8662306a36Sopenharmony_ci					       t.alarm);
8762306a36Sopenharmony_ci	timerfd_triggered(ctx);
8862306a36Sopenharmony_ci	return ALARMTIMER_NORESTART;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/*
9262306a36Sopenharmony_ci * Called when the clock was set to cancel the timers in the cancel
9362306a36Sopenharmony_ci * list. This will wake up processes waiting on these timers. The
9462306a36Sopenharmony_ci * wake-up requires ctx->ticks to be non zero, therefore we increment
9562306a36Sopenharmony_ci * it before calling wake_up_locked().
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_civoid timerfd_clock_was_set(void)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	ktime_t moffs = ktime_mono_to_real(0);
10062306a36Sopenharmony_ci	struct timerfd_ctx *ctx;
10162306a36Sopenharmony_ci	unsigned long flags;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	rcu_read_lock();
10462306a36Sopenharmony_ci	list_for_each_entry_rcu(ctx, &cancel_list, clist) {
10562306a36Sopenharmony_ci		if (!ctx->might_cancel)
10662306a36Sopenharmony_ci			continue;
10762306a36Sopenharmony_ci		spin_lock_irqsave(&ctx->wqh.lock, flags);
10862306a36Sopenharmony_ci		if (ctx->moffs != moffs) {
10962306a36Sopenharmony_ci			ctx->moffs = KTIME_MAX;
11062306a36Sopenharmony_ci			ctx->ticks++;
11162306a36Sopenharmony_ci			wake_up_locked_poll(&ctx->wqh, EPOLLIN);
11262306a36Sopenharmony_ci		}
11362306a36Sopenharmony_ci		spin_unlock_irqrestore(&ctx->wqh.lock, flags);
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci	rcu_read_unlock();
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic void timerfd_resume_work(struct work_struct *work)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	timerfd_clock_was_set();
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic DECLARE_WORK(timerfd_work, timerfd_resume_work);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/*
12662306a36Sopenharmony_ci * Invoked from timekeeping_resume(). Defer the actual update to work so
12762306a36Sopenharmony_ci * timerfd_clock_was_set() runs in task context.
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_civoid timerfd_resume(void)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	schedule_work(&timerfd_work);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic void __timerfd_remove_cancel(struct timerfd_ctx *ctx)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	if (ctx->might_cancel) {
13762306a36Sopenharmony_ci		ctx->might_cancel = false;
13862306a36Sopenharmony_ci		spin_lock(&cancel_lock);
13962306a36Sopenharmony_ci		list_del_rcu(&ctx->clist);
14062306a36Sopenharmony_ci		spin_unlock(&cancel_lock);
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic void timerfd_remove_cancel(struct timerfd_ctx *ctx)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	spin_lock(&ctx->cancel_lock);
14762306a36Sopenharmony_ci	__timerfd_remove_cancel(ctx);
14862306a36Sopenharmony_ci	spin_unlock(&ctx->cancel_lock);
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic bool timerfd_canceled(struct timerfd_ctx *ctx)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	if (!ctx->might_cancel || ctx->moffs != KTIME_MAX)
15462306a36Sopenharmony_ci		return false;
15562306a36Sopenharmony_ci	ctx->moffs = ktime_mono_to_real(0);
15662306a36Sopenharmony_ci	return true;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	spin_lock(&ctx->cancel_lock);
16262306a36Sopenharmony_ci	if ((ctx->clockid == CLOCK_REALTIME ||
16362306a36Sopenharmony_ci	     ctx->clockid == CLOCK_REALTIME_ALARM) &&
16462306a36Sopenharmony_ci	    (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
16562306a36Sopenharmony_ci		if (!ctx->might_cancel) {
16662306a36Sopenharmony_ci			ctx->might_cancel = true;
16762306a36Sopenharmony_ci			spin_lock(&cancel_lock);
16862306a36Sopenharmony_ci			list_add_rcu(&ctx->clist, &cancel_list);
16962306a36Sopenharmony_ci			spin_unlock(&cancel_lock);
17062306a36Sopenharmony_ci		}
17162306a36Sopenharmony_ci	} else {
17262306a36Sopenharmony_ci		__timerfd_remove_cancel(ctx);
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci	spin_unlock(&ctx->cancel_lock);
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	ktime_t remaining;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (isalarm(ctx))
18262306a36Sopenharmony_ci		remaining = alarm_expires_remaining(&ctx->t.alarm);
18362306a36Sopenharmony_ci	else
18462306a36Sopenharmony_ci		remaining = hrtimer_expires_remaining_adjusted(&ctx->t.tmr);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return remaining < 0 ? 0: remaining;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int timerfd_setup(struct timerfd_ctx *ctx, int flags,
19062306a36Sopenharmony_ci			 const struct itimerspec64 *ktmr)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	enum hrtimer_mode htmode;
19362306a36Sopenharmony_ci	ktime_t texp;
19462306a36Sopenharmony_ci	int clockid = ctx->clockid;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	htmode = (flags & TFD_TIMER_ABSTIME) ?
19762306a36Sopenharmony_ci		HRTIMER_MODE_ABS: HRTIMER_MODE_REL;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	texp = timespec64_to_ktime(ktmr->it_value);
20062306a36Sopenharmony_ci	ctx->expired = 0;
20162306a36Sopenharmony_ci	ctx->ticks = 0;
20262306a36Sopenharmony_ci	ctx->tintv = timespec64_to_ktime(ktmr->it_interval);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (isalarm(ctx)) {
20562306a36Sopenharmony_ci		alarm_init(&ctx->t.alarm,
20662306a36Sopenharmony_ci			   ctx->clockid == CLOCK_REALTIME_ALARM ?
20762306a36Sopenharmony_ci			   ALARM_REALTIME : ALARM_BOOTTIME,
20862306a36Sopenharmony_ci			   timerfd_alarmproc);
20962306a36Sopenharmony_ci	} else {
21062306a36Sopenharmony_ci		hrtimer_init(&ctx->t.tmr, clockid, htmode);
21162306a36Sopenharmony_ci		hrtimer_set_expires(&ctx->t.tmr, texp);
21262306a36Sopenharmony_ci		ctx->t.tmr.function = timerfd_tmrproc;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if (texp != 0) {
21662306a36Sopenharmony_ci		if (flags & TFD_TIMER_ABSTIME)
21762306a36Sopenharmony_ci			texp = timens_ktime_to_host(clockid, texp);
21862306a36Sopenharmony_ci		if (isalarm(ctx)) {
21962306a36Sopenharmony_ci			if (flags & TFD_TIMER_ABSTIME)
22062306a36Sopenharmony_ci				alarm_start(&ctx->t.alarm, texp);
22162306a36Sopenharmony_ci			else
22262306a36Sopenharmony_ci				alarm_start_relative(&ctx->t.alarm, texp);
22362306a36Sopenharmony_ci		} else {
22462306a36Sopenharmony_ci			hrtimer_start(&ctx->t.tmr, texp, htmode);
22562306a36Sopenharmony_ci		}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		if (timerfd_canceled(ctx))
22862306a36Sopenharmony_ci			return -ECANCELED;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	ctx->settime_flags = flags & TFD_SETTIME_FLAGS;
23262306a36Sopenharmony_ci	return 0;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic int timerfd_release(struct inode *inode, struct file *file)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	struct timerfd_ctx *ctx = file->private_data;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	timerfd_remove_cancel(ctx);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (isalarm(ctx))
24262306a36Sopenharmony_ci		alarm_cancel(&ctx->t.alarm);
24362306a36Sopenharmony_ci	else
24462306a36Sopenharmony_ci		hrtimer_cancel(&ctx->t.tmr);
24562306a36Sopenharmony_ci	kfree_rcu(ctx, rcu);
24662306a36Sopenharmony_ci	return 0;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic __poll_t timerfd_poll(struct file *file, poll_table *wait)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct timerfd_ctx *ctx = file->private_data;
25262306a36Sopenharmony_ci	__poll_t events = 0;
25362306a36Sopenharmony_ci	unsigned long flags;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	poll_wait(file, &ctx->wqh, wait);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	spin_lock_irqsave(&ctx->wqh.lock, flags);
25862306a36Sopenharmony_ci	if (ctx->ticks)
25962306a36Sopenharmony_ci		events |= EPOLLIN;
26062306a36Sopenharmony_ci	spin_unlock_irqrestore(&ctx->wqh.lock, flags);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	return events;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
26662306a36Sopenharmony_ci			    loff_t *ppos)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	struct timerfd_ctx *ctx = file->private_data;
26962306a36Sopenharmony_ci	ssize_t res;
27062306a36Sopenharmony_ci	u64 ticks = 0;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (count < sizeof(ticks))
27362306a36Sopenharmony_ci		return -EINVAL;
27462306a36Sopenharmony_ci	spin_lock_irq(&ctx->wqh.lock);
27562306a36Sopenharmony_ci	if (file->f_flags & O_NONBLOCK)
27662306a36Sopenharmony_ci		res = -EAGAIN;
27762306a36Sopenharmony_ci	else
27862306a36Sopenharmony_ci		res = wait_event_interruptible_locked_irq(ctx->wqh, ctx->ticks);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/*
28162306a36Sopenharmony_ci	 * If clock has changed, we do not care about the
28262306a36Sopenharmony_ci	 * ticks and we do not rearm the timer. Userspace must
28362306a36Sopenharmony_ci	 * reevaluate anyway.
28462306a36Sopenharmony_ci	 */
28562306a36Sopenharmony_ci	if (timerfd_canceled(ctx)) {
28662306a36Sopenharmony_ci		ctx->ticks = 0;
28762306a36Sopenharmony_ci		ctx->expired = 0;
28862306a36Sopenharmony_ci		res = -ECANCELED;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (ctx->ticks) {
29262306a36Sopenharmony_ci		ticks = ctx->ticks;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		if (ctx->expired && ctx->tintv) {
29562306a36Sopenharmony_ci			/*
29662306a36Sopenharmony_ci			 * If tintv != 0, this is a periodic timer that
29762306a36Sopenharmony_ci			 * needs to be re-armed. We avoid doing it in the timer
29862306a36Sopenharmony_ci			 * callback to avoid DoS attacks specifying a very
29962306a36Sopenharmony_ci			 * short timer period.
30062306a36Sopenharmony_ci			 */
30162306a36Sopenharmony_ci			if (isalarm(ctx)) {
30262306a36Sopenharmony_ci				ticks += alarm_forward_now(
30362306a36Sopenharmony_ci					&ctx->t.alarm, ctx->tintv) - 1;
30462306a36Sopenharmony_ci				alarm_restart(&ctx->t.alarm);
30562306a36Sopenharmony_ci			} else {
30662306a36Sopenharmony_ci				ticks += hrtimer_forward_now(&ctx->t.tmr,
30762306a36Sopenharmony_ci							     ctx->tintv) - 1;
30862306a36Sopenharmony_ci				hrtimer_restart(&ctx->t.tmr);
30962306a36Sopenharmony_ci			}
31062306a36Sopenharmony_ci		}
31162306a36Sopenharmony_ci		ctx->expired = 0;
31262306a36Sopenharmony_ci		ctx->ticks = 0;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci	spin_unlock_irq(&ctx->wqh.lock);
31562306a36Sopenharmony_ci	if (ticks)
31662306a36Sopenharmony_ci		res = put_user(ticks, (u64 __user *) buf) ? -EFAULT: sizeof(ticks);
31762306a36Sopenharmony_ci	return res;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
32162306a36Sopenharmony_cistatic void timerfd_show(struct seq_file *m, struct file *file)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct timerfd_ctx *ctx = file->private_data;
32462306a36Sopenharmony_ci	struct timespec64 value, interval;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	spin_lock_irq(&ctx->wqh.lock);
32762306a36Sopenharmony_ci	value = ktime_to_timespec64(timerfd_get_remaining(ctx));
32862306a36Sopenharmony_ci	interval = ktime_to_timespec64(ctx->tintv);
32962306a36Sopenharmony_ci	spin_unlock_irq(&ctx->wqh.lock);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	seq_printf(m,
33262306a36Sopenharmony_ci		   "clockid: %d\n"
33362306a36Sopenharmony_ci		   "ticks: %llu\n"
33462306a36Sopenharmony_ci		   "settime flags: 0%o\n"
33562306a36Sopenharmony_ci		   "it_value: (%llu, %llu)\n"
33662306a36Sopenharmony_ci		   "it_interval: (%llu, %llu)\n",
33762306a36Sopenharmony_ci		   ctx->clockid,
33862306a36Sopenharmony_ci		   (unsigned long long)ctx->ticks,
33962306a36Sopenharmony_ci		   ctx->settime_flags,
34062306a36Sopenharmony_ci		   (unsigned long long)value.tv_sec,
34162306a36Sopenharmony_ci		   (unsigned long long)value.tv_nsec,
34262306a36Sopenharmony_ci		   (unsigned long long)interval.tv_sec,
34362306a36Sopenharmony_ci		   (unsigned long long)interval.tv_nsec);
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci#else
34662306a36Sopenharmony_ci#define timerfd_show NULL
34762306a36Sopenharmony_ci#endif
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci#ifdef CONFIG_CHECKPOINT_RESTORE
35062306a36Sopenharmony_cistatic long timerfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct timerfd_ctx *ctx = file->private_data;
35362306a36Sopenharmony_ci	int ret = 0;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	switch (cmd) {
35662306a36Sopenharmony_ci	case TFD_IOC_SET_TICKS: {
35762306a36Sopenharmony_ci		u64 ticks;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		if (copy_from_user(&ticks, (u64 __user *)arg, sizeof(ticks)))
36062306a36Sopenharmony_ci			return -EFAULT;
36162306a36Sopenharmony_ci		if (!ticks)
36262306a36Sopenharmony_ci			return -EINVAL;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci		spin_lock_irq(&ctx->wqh.lock);
36562306a36Sopenharmony_ci		if (!timerfd_canceled(ctx)) {
36662306a36Sopenharmony_ci			ctx->ticks = ticks;
36762306a36Sopenharmony_ci			wake_up_locked_poll(&ctx->wqh, EPOLLIN);
36862306a36Sopenharmony_ci		} else
36962306a36Sopenharmony_ci			ret = -ECANCELED;
37062306a36Sopenharmony_ci		spin_unlock_irq(&ctx->wqh.lock);
37162306a36Sopenharmony_ci		break;
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci	default:
37462306a36Sopenharmony_ci		ret = -ENOTTY;
37562306a36Sopenharmony_ci		break;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	return ret;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci#else
38162306a36Sopenharmony_ci#define timerfd_ioctl NULL
38262306a36Sopenharmony_ci#endif
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic const struct file_operations timerfd_fops = {
38562306a36Sopenharmony_ci	.release	= timerfd_release,
38662306a36Sopenharmony_ci	.poll		= timerfd_poll,
38762306a36Sopenharmony_ci	.read		= timerfd_read,
38862306a36Sopenharmony_ci	.llseek		= noop_llseek,
38962306a36Sopenharmony_ci	.show_fdinfo	= timerfd_show,
39062306a36Sopenharmony_ci	.unlocked_ioctl	= timerfd_ioctl,
39162306a36Sopenharmony_ci};
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic int timerfd_fget(int fd, struct fd *p)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	struct fd f = fdget(fd);
39662306a36Sopenharmony_ci	if (!f.file)
39762306a36Sopenharmony_ci		return -EBADF;
39862306a36Sopenharmony_ci	if (f.file->f_op != &timerfd_fops) {
39962306a36Sopenharmony_ci		fdput(f);
40062306a36Sopenharmony_ci		return -EINVAL;
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci	*p = f;
40362306a36Sopenharmony_ci	return 0;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ciSYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	int ufd;
40962306a36Sopenharmony_ci	struct timerfd_ctx *ctx;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/* Check the TFD_* constants for consistency.  */
41262306a36Sopenharmony_ci	BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC);
41362306a36Sopenharmony_ci	BUILD_BUG_ON(TFD_NONBLOCK != O_NONBLOCK);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if ((flags & ~TFD_CREATE_FLAGS) ||
41662306a36Sopenharmony_ci	    (clockid != CLOCK_MONOTONIC &&
41762306a36Sopenharmony_ci	     clockid != CLOCK_REALTIME &&
41862306a36Sopenharmony_ci	     clockid != CLOCK_REALTIME_ALARM &&
41962306a36Sopenharmony_ci	     clockid != CLOCK_BOOTTIME &&
42062306a36Sopenharmony_ci	     clockid != CLOCK_BOOTTIME_ALARM))
42162306a36Sopenharmony_ci		return -EINVAL;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if ((clockid == CLOCK_REALTIME_ALARM ||
42462306a36Sopenharmony_ci	     clockid == CLOCK_BOOTTIME_ALARM) &&
42562306a36Sopenharmony_ci	    !capable(CAP_WAKE_ALARM))
42662306a36Sopenharmony_ci		return -EPERM;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
42962306a36Sopenharmony_ci	if (!ctx)
43062306a36Sopenharmony_ci		return -ENOMEM;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	init_waitqueue_head(&ctx->wqh);
43362306a36Sopenharmony_ci	spin_lock_init(&ctx->cancel_lock);
43462306a36Sopenharmony_ci	ctx->clockid = clockid;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (isalarm(ctx))
43762306a36Sopenharmony_ci		alarm_init(&ctx->t.alarm,
43862306a36Sopenharmony_ci			   ctx->clockid == CLOCK_REALTIME_ALARM ?
43962306a36Sopenharmony_ci			   ALARM_REALTIME : ALARM_BOOTTIME,
44062306a36Sopenharmony_ci			   timerfd_alarmproc);
44162306a36Sopenharmony_ci	else
44262306a36Sopenharmony_ci		hrtimer_init(&ctx->t.tmr, clockid, HRTIMER_MODE_ABS);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	ctx->moffs = ktime_mono_to_real(0);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx,
44762306a36Sopenharmony_ci			       O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS));
44862306a36Sopenharmony_ci	if (ufd < 0)
44962306a36Sopenharmony_ci		kfree(ctx);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	return ufd;
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic int do_timerfd_settime(int ufd, int flags,
45562306a36Sopenharmony_ci		const struct itimerspec64 *new,
45662306a36Sopenharmony_ci		struct itimerspec64 *old)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	struct fd f;
45962306a36Sopenharmony_ci	struct timerfd_ctx *ctx;
46062306a36Sopenharmony_ci	int ret;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	if ((flags & ~TFD_SETTIME_FLAGS) ||
46362306a36Sopenharmony_ci		 !itimerspec64_valid(new))
46462306a36Sopenharmony_ci		return -EINVAL;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	ret = timerfd_fget(ufd, &f);
46762306a36Sopenharmony_ci	if (ret)
46862306a36Sopenharmony_ci		return ret;
46962306a36Sopenharmony_ci	ctx = f.file->private_data;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (isalarm(ctx) && !capable(CAP_WAKE_ALARM)) {
47262306a36Sopenharmony_ci		fdput(f);
47362306a36Sopenharmony_ci		return -EPERM;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	timerfd_setup_cancel(ctx, flags);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	/*
47962306a36Sopenharmony_ci	 * We need to stop the existing timer before reprogramming
48062306a36Sopenharmony_ci	 * it to the new values.
48162306a36Sopenharmony_ci	 */
48262306a36Sopenharmony_ci	for (;;) {
48362306a36Sopenharmony_ci		spin_lock_irq(&ctx->wqh.lock);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci		if (isalarm(ctx)) {
48662306a36Sopenharmony_ci			if (alarm_try_to_cancel(&ctx->t.alarm) >= 0)
48762306a36Sopenharmony_ci				break;
48862306a36Sopenharmony_ci		} else {
48962306a36Sopenharmony_ci			if (hrtimer_try_to_cancel(&ctx->t.tmr) >= 0)
49062306a36Sopenharmony_ci				break;
49162306a36Sopenharmony_ci		}
49262306a36Sopenharmony_ci		spin_unlock_irq(&ctx->wqh.lock);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		if (isalarm(ctx))
49562306a36Sopenharmony_ci			hrtimer_cancel_wait_running(&ctx->t.alarm.timer);
49662306a36Sopenharmony_ci		else
49762306a36Sopenharmony_ci			hrtimer_cancel_wait_running(&ctx->t.tmr);
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	/*
50162306a36Sopenharmony_ci	 * If the timer is expired and it's periodic, we need to advance it
50262306a36Sopenharmony_ci	 * because the caller may want to know the previous expiration time.
50362306a36Sopenharmony_ci	 * We do not update "ticks" and "expired" since the timer will be
50462306a36Sopenharmony_ci	 * re-programmed again in the following timerfd_setup() call.
50562306a36Sopenharmony_ci	 */
50662306a36Sopenharmony_ci	if (ctx->expired && ctx->tintv) {
50762306a36Sopenharmony_ci		if (isalarm(ctx))
50862306a36Sopenharmony_ci			alarm_forward_now(&ctx->t.alarm, ctx->tintv);
50962306a36Sopenharmony_ci		else
51062306a36Sopenharmony_ci			hrtimer_forward_now(&ctx->t.tmr, ctx->tintv);
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	old->it_value = ktime_to_timespec64(timerfd_get_remaining(ctx));
51462306a36Sopenharmony_ci	old->it_interval = ktime_to_timespec64(ctx->tintv);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	/*
51762306a36Sopenharmony_ci	 * Re-program the timer to the new value ...
51862306a36Sopenharmony_ci	 */
51962306a36Sopenharmony_ci	ret = timerfd_setup(ctx, flags, new);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	spin_unlock_irq(&ctx->wqh.lock);
52262306a36Sopenharmony_ci	fdput(f);
52362306a36Sopenharmony_ci	return ret;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic int do_timerfd_gettime(int ufd, struct itimerspec64 *t)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	struct fd f;
52962306a36Sopenharmony_ci	struct timerfd_ctx *ctx;
53062306a36Sopenharmony_ci	int ret = timerfd_fget(ufd, &f);
53162306a36Sopenharmony_ci	if (ret)
53262306a36Sopenharmony_ci		return ret;
53362306a36Sopenharmony_ci	ctx = f.file->private_data;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	spin_lock_irq(&ctx->wqh.lock);
53662306a36Sopenharmony_ci	if (ctx->expired && ctx->tintv) {
53762306a36Sopenharmony_ci		ctx->expired = 0;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci		if (isalarm(ctx)) {
54062306a36Sopenharmony_ci			ctx->ticks +=
54162306a36Sopenharmony_ci				alarm_forward_now(
54262306a36Sopenharmony_ci					&ctx->t.alarm, ctx->tintv) - 1;
54362306a36Sopenharmony_ci			alarm_restart(&ctx->t.alarm);
54462306a36Sopenharmony_ci		} else {
54562306a36Sopenharmony_ci			ctx->ticks +=
54662306a36Sopenharmony_ci				hrtimer_forward_now(&ctx->t.tmr, ctx->tintv)
54762306a36Sopenharmony_ci				- 1;
54862306a36Sopenharmony_ci			hrtimer_restart(&ctx->t.tmr);
54962306a36Sopenharmony_ci		}
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci	t->it_value = ktime_to_timespec64(timerfd_get_remaining(ctx));
55262306a36Sopenharmony_ci	t->it_interval = ktime_to_timespec64(ctx->tintv);
55362306a36Sopenharmony_ci	spin_unlock_irq(&ctx->wqh.lock);
55462306a36Sopenharmony_ci	fdput(f);
55562306a36Sopenharmony_ci	return 0;
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ciSYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
55962306a36Sopenharmony_ci		const struct __kernel_itimerspec __user *, utmr,
56062306a36Sopenharmony_ci		struct __kernel_itimerspec __user *, otmr)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	struct itimerspec64 new, old;
56362306a36Sopenharmony_ci	int ret;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	if (get_itimerspec64(&new, utmr))
56662306a36Sopenharmony_ci		return -EFAULT;
56762306a36Sopenharmony_ci	ret = do_timerfd_settime(ufd, flags, &new, &old);
56862306a36Sopenharmony_ci	if (ret)
56962306a36Sopenharmony_ci		return ret;
57062306a36Sopenharmony_ci	if (otmr && put_itimerspec64(&old, otmr))
57162306a36Sopenharmony_ci		return -EFAULT;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	return ret;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ciSYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct __kernel_itimerspec __user *, otmr)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	struct itimerspec64 kotmr;
57962306a36Sopenharmony_ci	int ret = do_timerfd_gettime(ufd, &kotmr);
58062306a36Sopenharmony_ci	if (ret)
58162306a36Sopenharmony_ci		return ret;
58262306a36Sopenharmony_ci	return put_itimerspec64(&kotmr, otmr) ? -EFAULT : 0;
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci#ifdef CONFIG_COMPAT_32BIT_TIME
58662306a36Sopenharmony_ciSYSCALL_DEFINE4(timerfd_settime32, int, ufd, int, flags,
58762306a36Sopenharmony_ci		const struct old_itimerspec32 __user *, utmr,
58862306a36Sopenharmony_ci		struct old_itimerspec32 __user *, otmr)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct itimerspec64 new, old;
59162306a36Sopenharmony_ci	int ret;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (get_old_itimerspec32(&new, utmr))
59462306a36Sopenharmony_ci		return -EFAULT;
59562306a36Sopenharmony_ci	ret = do_timerfd_settime(ufd, flags, &new, &old);
59662306a36Sopenharmony_ci	if (ret)
59762306a36Sopenharmony_ci		return ret;
59862306a36Sopenharmony_ci	if (otmr && put_old_itimerspec32(&old, otmr))
59962306a36Sopenharmony_ci		return -EFAULT;
60062306a36Sopenharmony_ci	return ret;
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ciSYSCALL_DEFINE2(timerfd_gettime32, int, ufd,
60462306a36Sopenharmony_ci		struct old_itimerspec32 __user *, otmr)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	struct itimerspec64 kotmr;
60762306a36Sopenharmony_ci	int ret = do_timerfd_gettime(ufd, &kotmr);
60862306a36Sopenharmony_ci	if (ret)
60962306a36Sopenharmony_ci		return ret;
61062306a36Sopenharmony_ci	return put_old_itimerspec32(&kotmr, otmr) ? -EFAULT : 0;
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci#endif
613