18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  fs/timerfd.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *  Thanks to Thomas Gleixner for code reviews and useful comments.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/alarmtimer.h>
138c2ecf20Sopenharmony_ci#include <linux/file.h>
148c2ecf20Sopenharmony_ci#include <linux/poll.h>
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <linux/fs.h>
178c2ecf20Sopenharmony_ci#include <linux/sched.h>
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci#include <linux/list.h>
218c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
228c2ecf20Sopenharmony_ci#include <linux/time.h>
238c2ecf20Sopenharmony_ci#include <linux/hrtimer.h>
248c2ecf20Sopenharmony_ci#include <linux/anon_inodes.h>
258c2ecf20Sopenharmony_ci#include <linux/timerfd.h>
268c2ecf20Sopenharmony_ci#include <linux/syscalls.h>
278c2ecf20Sopenharmony_ci#include <linux/compat.h>
288c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
298c2ecf20Sopenharmony_ci#include <linux/time_namespace.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistruct timerfd_ctx {
328c2ecf20Sopenharmony_ci	union {
338c2ecf20Sopenharmony_ci		struct hrtimer tmr;
348c2ecf20Sopenharmony_ci		struct alarm alarm;
358c2ecf20Sopenharmony_ci	} t;
368c2ecf20Sopenharmony_ci	ktime_t tintv;
378c2ecf20Sopenharmony_ci	ktime_t moffs;
388c2ecf20Sopenharmony_ci	wait_queue_head_t wqh;
398c2ecf20Sopenharmony_ci	u64 ticks;
408c2ecf20Sopenharmony_ci	int clockid;
418c2ecf20Sopenharmony_ci	short unsigned expired;
428c2ecf20Sopenharmony_ci	short unsigned settime_flags;	/* to show in fdinfo */
438c2ecf20Sopenharmony_ci	struct rcu_head rcu;
448c2ecf20Sopenharmony_ci	struct list_head clist;
458c2ecf20Sopenharmony_ci	spinlock_t cancel_lock;
468c2ecf20Sopenharmony_ci	bool might_cancel;
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic LIST_HEAD(cancel_list);
508c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(cancel_lock);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic inline bool isalarm(struct timerfd_ctx *ctx)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	return ctx->clockid == CLOCK_REALTIME_ALARM ||
558c2ecf20Sopenharmony_ci		ctx->clockid == CLOCK_BOOTTIME_ALARM;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/*
598c2ecf20Sopenharmony_ci * This gets called when the timer event triggers. We set the "expired"
608c2ecf20Sopenharmony_ci * flag, but we do not re-arm the timer (in case it's necessary,
618c2ecf20Sopenharmony_ci * tintv != 0) until the timer is accessed.
628c2ecf20Sopenharmony_ci */
638c2ecf20Sopenharmony_cistatic void timerfd_triggered(struct timerfd_ctx *ctx)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	unsigned long flags;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ctx->wqh.lock, flags);
688c2ecf20Sopenharmony_ci	ctx->expired = 1;
698c2ecf20Sopenharmony_ci	ctx->ticks++;
708c2ecf20Sopenharmony_ci	wake_up_locked_poll(&ctx->wqh, EPOLLIN);
718c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ctx->wqh.lock, flags);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx,
778c2ecf20Sopenharmony_ci					       t.tmr);
788c2ecf20Sopenharmony_ci	timerfd_triggered(ctx);
798c2ecf20Sopenharmony_ci	return HRTIMER_NORESTART;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic enum alarmtimer_restart timerfd_alarmproc(struct alarm *alarm,
838c2ecf20Sopenharmony_ci	ktime_t now)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct timerfd_ctx *ctx = container_of(alarm, struct timerfd_ctx,
868c2ecf20Sopenharmony_ci					       t.alarm);
878c2ecf20Sopenharmony_ci	timerfd_triggered(ctx);
888c2ecf20Sopenharmony_ci	return ALARMTIMER_NORESTART;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/*
928c2ecf20Sopenharmony_ci * Called when the clock was set to cancel the timers in the cancel
938c2ecf20Sopenharmony_ci * list. This will wake up processes waiting on these timers. The
948c2ecf20Sopenharmony_ci * wake-up requires ctx->ticks to be non zero, therefore we increment
958c2ecf20Sopenharmony_ci * it before calling wake_up_locked().
968c2ecf20Sopenharmony_ci */
978c2ecf20Sopenharmony_civoid timerfd_clock_was_set(void)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	ktime_t moffs = ktime_mono_to_real(0);
1008c2ecf20Sopenharmony_ci	struct timerfd_ctx *ctx;
1018c2ecf20Sopenharmony_ci	unsigned long flags;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	rcu_read_lock();
1048c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(ctx, &cancel_list, clist) {
1058c2ecf20Sopenharmony_ci		if (!ctx->might_cancel)
1068c2ecf20Sopenharmony_ci			continue;
1078c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ctx->wqh.lock, flags);
1088c2ecf20Sopenharmony_ci		if (ctx->moffs != moffs) {
1098c2ecf20Sopenharmony_ci			ctx->moffs = KTIME_MAX;
1108c2ecf20Sopenharmony_ci			ctx->ticks++;
1118c2ecf20Sopenharmony_ci			wake_up_locked_poll(&ctx->wqh, EPOLLIN);
1128c2ecf20Sopenharmony_ci		}
1138c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ctx->wqh.lock, flags);
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci	rcu_read_unlock();
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic void __timerfd_remove_cancel(struct timerfd_ctx *ctx)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	if (ctx->might_cancel) {
1218c2ecf20Sopenharmony_ci		ctx->might_cancel = false;
1228c2ecf20Sopenharmony_ci		spin_lock(&cancel_lock);
1238c2ecf20Sopenharmony_ci		list_del_rcu(&ctx->clist);
1248c2ecf20Sopenharmony_ci		spin_unlock(&cancel_lock);
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic void timerfd_remove_cancel(struct timerfd_ctx *ctx)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	spin_lock(&ctx->cancel_lock);
1318c2ecf20Sopenharmony_ci	__timerfd_remove_cancel(ctx);
1328c2ecf20Sopenharmony_ci	spin_unlock(&ctx->cancel_lock);
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic bool timerfd_canceled(struct timerfd_ctx *ctx)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	if (!ctx->might_cancel || ctx->moffs != KTIME_MAX)
1388c2ecf20Sopenharmony_ci		return false;
1398c2ecf20Sopenharmony_ci	ctx->moffs = ktime_mono_to_real(0);
1408c2ecf20Sopenharmony_ci	return true;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	spin_lock(&ctx->cancel_lock);
1468c2ecf20Sopenharmony_ci	if ((ctx->clockid == CLOCK_REALTIME ||
1478c2ecf20Sopenharmony_ci	     ctx->clockid == CLOCK_REALTIME_ALARM) &&
1488c2ecf20Sopenharmony_ci	    (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
1498c2ecf20Sopenharmony_ci		if (!ctx->might_cancel) {
1508c2ecf20Sopenharmony_ci			ctx->might_cancel = true;
1518c2ecf20Sopenharmony_ci			spin_lock(&cancel_lock);
1528c2ecf20Sopenharmony_ci			list_add_rcu(&ctx->clist, &cancel_list);
1538c2ecf20Sopenharmony_ci			spin_unlock(&cancel_lock);
1548c2ecf20Sopenharmony_ci		}
1558c2ecf20Sopenharmony_ci	} else {
1568c2ecf20Sopenharmony_ci		__timerfd_remove_cancel(ctx);
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci	spin_unlock(&ctx->cancel_lock);
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	ktime_t remaining;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	if (isalarm(ctx))
1668c2ecf20Sopenharmony_ci		remaining = alarm_expires_remaining(&ctx->t.alarm);
1678c2ecf20Sopenharmony_ci	else
1688c2ecf20Sopenharmony_ci		remaining = hrtimer_expires_remaining_adjusted(&ctx->t.tmr);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return remaining < 0 ? 0: remaining;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic int timerfd_setup(struct timerfd_ctx *ctx, int flags,
1748c2ecf20Sopenharmony_ci			 const struct itimerspec64 *ktmr)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	enum hrtimer_mode htmode;
1778c2ecf20Sopenharmony_ci	ktime_t texp;
1788c2ecf20Sopenharmony_ci	int clockid = ctx->clockid;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	htmode = (flags & TFD_TIMER_ABSTIME) ?
1818c2ecf20Sopenharmony_ci		HRTIMER_MODE_ABS: HRTIMER_MODE_REL;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	texp = timespec64_to_ktime(ktmr->it_value);
1848c2ecf20Sopenharmony_ci	ctx->expired = 0;
1858c2ecf20Sopenharmony_ci	ctx->ticks = 0;
1868c2ecf20Sopenharmony_ci	ctx->tintv = timespec64_to_ktime(ktmr->it_interval);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (isalarm(ctx)) {
1898c2ecf20Sopenharmony_ci		alarm_init(&ctx->t.alarm,
1908c2ecf20Sopenharmony_ci			   ctx->clockid == CLOCK_REALTIME_ALARM ?
1918c2ecf20Sopenharmony_ci			   ALARM_REALTIME : ALARM_BOOTTIME,
1928c2ecf20Sopenharmony_ci			   timerfd_alarmproc);
1938c2ecf20Sopenharmony_ci	} else {
1948c2ecf20Sopenharmony_ci		hrtimer_init(&ctx->t.tmr, clockid, htmode);
1958c2ecf20Sopenharmony_ci		hrtimer_set_expires(&ctx->t.tmr, texp);
1968c2ecf20Sopenharmony_ci		ctx->t.tmr.function = timerfd_tmrproc;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	if (texp != 0) {
2008c2ecf20Sopenharmony_ci		if (flags & TFD_TIMER_ABSTIME)
2018c2ecf20Sopenharmony_ci			texp = timens_ktime_to_host(clockid, texp);
2028c2ecf20Sopenharmony_ci		if (isalarm(ctx)) {
2038c2ecf20Sopenharmony_ci			if (flags & TFD_TIMER_ABSTIME)
2048c2ecf20Sopenharmony_ci				alarm_start(&ctx->t.alarm, texp);
2058c2ecf20Sopenharmony_ci			else
2068c2ecf20Sopenharmony_ci				alarm_start_relative(&ctx->t.alarm, texp);
2078c2ecf20Sopenharmony_ci		} else {
2088c2ecf20Sopenharmony_ci			hrtimer_start(&ctx->t.tmr, texp, htmode);
2098c2ecf20Sopenharmony_ci		}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci		if (timerfd_canceled(ctx))
2128c2ecf20Sopenharmony_ci			return -ECANCELED;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	ctx->settime_flags = flags & TFD_SETTIME_FLAGS;
2168c2ecf20Sopenharmony_ci	return 0;
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic int timerfd_release(struct inode *inode, struct file *file)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct timerfd_ctx *ctx = file->private_data;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	timerfd_remove_cancel(ctx);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (isalarm(ctx))
2268c2ecf20Sopenharmony_ci		alarm_cancel(&ctx->t.alarm);
2278c2ecf20Sopenharmony_ci	else
2288c2ecf20Sopenharmony_ci		hrtimer_cancel(&ctx->t.tmr);
2298c2ecf20Sopenharmony_ci	kfree_rcu(ctx, rcu);
2308c2ecf20Sopenharmony_ci	return 0;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic __poll_t timerfd_poll(struct file *file, poll_table *wait)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct timerfd_ctx *ctx = file->private_data;
2368c2ecf20Sopenharmony_ci	__poll_t events = 0;
2378c2ecf20Sopenharmony_ci	unsigned long flags;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	poll_wait(file, &ctx->wqh, wait);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ctx->wqh.lock, flags);
2428c2ecf20Sopenharmony_ci	if (ctx->ticks)
2438c2ecf20Sopenharmony_ci		events |= EPOLLIN;
2448c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ctx->wqh.lock, flags);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	return events;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
2508c2ecf20Sopenharmony_ci			    loff_t *ppos)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	struct timerfd_ctx *ctx = file->private_data;
2538c2ecf20Sopenharmony_ci	ssize_t res;
2548c2ecf20Sopenharmony_ci	u64 ticks = 0;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if (count < sizeof(ticks))
2578c2ecf20Sopenharmony_ci		return -EINVAL;
2588c2ecf20Sopenharmony_ci	spin_lock_irq(&ctx->wqh.lock);
2598c2ecf20Sopenharmony_ci	if (file->f_flags & O_NONBLOCK)
2608c2ecf20Sopenharmony_ci		res = -EAGAIN;
2618c2ecf20Sopenharmony_ci	else
2628c2ecf20Sopenharmony_ci		res = wait_event_interruptible_locked_irq(ctx->wqh, ctx->ticks);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	/*
2658c2ecf20Sopenharmony_ci	 * If clock has changed, we do not care about the
2668c2ecf20Sopenharmony_ci	 * ticks and we do not rearm the timer. Userspace must
2678c2ecf20Sopenharmony_ci	 * reevaluate anyway.
2688c2ecf20Sopenharmony_ci	 */
2698c2ecf20Sopenharmony_ci	if (timerfd_canceled(ctx)) {
2708c2ecf20Sopenharmony_ci		ctx->ticks = 0;
2718c2ecf20Sopenharmony_ci		ctx->expired = 0;
2728c2ecf20Sopenharmony_ci		res = -ECANCELED;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (ctx->ticks) {
2768c2ecf20Sopenharmony_ci		ticks = ctx->ticks;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci		if (ctx->expired && ctx->tintv) {
2798c2ecf20Sopenharmony_ci			/*
2808c2ecf20Sopenharmony_ci			 * If tintv != 0, this is a periodic timer that
2818c2ecf20Sopenharmony_ci			 * needs to be re-armed. We avoid doing it in the timer
2828c2ecf20Sopenharmony_ci			 * callback to avoid DoS attacks specifying a very
2838c2ecf20Sopenharmony_ci			 * short timer period.
2848c2ecf20Sopenharmony_ci			 */
2858c2ecf20Sopenharmony_ci			if (isalarm(ctx)) {
2868c2ecf20Sopenharmony_ci				ticks += alarm_forward_now(
2878c2ecf20Sopenharmony_ci					&ctx->t.alarm, ctx->tintv) - 1;
2888c2ecf20Sopenharmony_ci				alarm_restart(&ctx->t.alarm);
2898c2ecf20Sopenharmony_ci			} else {
2908c2ecf20Sopenharmony_ci				ticks += hrtimer_forward_now(&ctx->t.tmr,
2918c2ecf20Sopenharmony_ci							     ctx->tintv) - 1;
2928c2ecf20Sopenharmony_ci				hrtimer_restart(&ctx->t.tmr);
2938c2ecf20Sopenharmony_ci			}
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci		ctx->expired = 0;
2968c2ecf20Sopenharmony_ci		ctx->ticks = 0;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci	spin_unlock_irq(&ctx->wqh.lock);
2998c2ecf20Sopenharmony_ci	if (ticks)
3008c2ecf20Sopenharmony_ci		res = put_user(ticks, (u64 __user *) buf) ? -EFAULT: sizeof(ticks);
3018c2ecf20Sopenharmony_ci	return res;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
3058c2ecf20Sopenharmony_cistatic void timerfd_show(struct seq_file *m, struct file *file)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	struct timerfd_ctx *ctx = file->private_data;
3088c2ecf20Sopenharmony_ci	struct timespec64 value, interval;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	spin_lock_irq(&ctx->wqh.lock);
3118c2ecf20Sopenharmony_ci	value = ktime_to_timespec64(timerfd_get_remaining(ctx));
3128c2ecf20Sopenharmony_ci	interval = ktime_to_timespec64(ctx->tintv);
3138c2ecf20Sopenharmony_ci	spin_unlock_irq(&ctx->wqh.lock);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	seq_printf(m,
3168c2ecf20Sopenharmony_ci		   "clockid: %d\n"
3178c2ecf20Sopenharmony_ci		   "ticks: %llu\n"
3188c2ecf20Sopenharmony_ci		   "settime flags: 0%o\n"
3198c2ecf20Sopenharmony_ci		   "it_value: (%llu, %llu)\n"
3208c2ecf20Sopenharmony_ci		   "it_interval: (%llu, %llu)\n",
3218c2ecf20Sopenharmony_ci		   ctx->clockid,
3228c2ecf20Sopenharmony_ci		   (unsigned long long)ctx->ticks,
3238c2ecf20Sopenharmony_ci		   ctx->settime_flags,
3248c2ecf20Sopenharmony_ci		   (unsigned long long)value.tv_sec,
3258c2ecf20Sopenharmony_ci		   (unsigned long long)value.tv_nsec,
3268c2ecf20Sopenharmony_ci		   (unsigned long long)interval.tv_sec,
3278c2ecf20Sopenharmony_ci		   (unsigned long long)interval.tv_nsec);
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci#else
3308c2ecf20Sopenharmony_ci#define timerfd_show NULL
3318c2ecf20Sopenharmony_ci#endif
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci#ifdef CONFIG_CHECKPOINT_RESTORE
3348c2ecf20Sopenharmony_cistatic long timerfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	struct timerfd_ctx *ctx = file->private_data;
3378c2ecf20Sopenharmony_ci	int ret = 0;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	switch (cmd) {
3408c2ecf20Sopenharmony_ci	case TFD_IOC_SET_TICKS: {
3418c2ecf20Sopenharmony_ci		u64 ticks;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci		if (copy_from_user(&ticks, (u64 __user *)arg, sizeof(ticks)))
3448c2ecf20Sopenharmony_ci			return -EFAULT;
3458c2ecf20Sopenharmony_ci		if (!ticks)
3468c2ecf20Sopenharmony_ci			return -EINVAL;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		spin_lock_irq(&ctx->wqh.lock);
3498c2ecf20Sopenharmony_ci		if (!timerfd_canceled(ctx)) {
3508c2ecf20Sopenharmony_ci			ctx->ticks = ticks;
3518c2ecf20Sopenharmony_ci			wake_up_locked_poll(&ctx->wqh, EPOLLIN);
3528c2ecf20Sopenharmony_ci		} else
3538c2ecf20Sopenharmony_ci			ret = -ECANCELED;
3548c2ecf20Sopenharmony_ci		spin_unlock_irq(&ctx->wqh.lock);
3558c2ecf20Sopenharmony_ci		break;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci	default:
3588c2ecf20Sopenharmony_ci		ret = -ENOTTY;
3598c2ecf20Sopenharmony_ci		break;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	return ret;
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci#else
3658c2ecf20Sopenharmony_ci#define timerfd_ioctl NULL
3668c2ecf20Sopenharmony_ci#endif
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic const struct file_operations timerfd_fops = {
3698c2ecf20Sopenharmony_ci	.release	= timerfd_release,
3708c2ecf20Sopenharmony_ci	.poll		= timerfd_poll,
3718c2ecf20Sopenharmony_ci	.read		= timerfd_read,
3728c2ecf20Sopenharmony_ci	.llseek		= noop_llseek,
3738c2ecf20Sopenharmony_ci	.show_fdinfo	= timerfd_show,
3748c2ecf20Sopenharmony_ci	.unlocked_ioctl	= timerfd_ioctl,
3758c2ecf20Sopenharmony_ci};
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cistatic int timerfd_fget(int fd, struct fd *p)
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	struct fd f = fdget(fd);
3808c2ecf20Sopenharmony_ci	if (!f.file)
3818c2ecf20Sopenharmony_ci		return -EBADF;
3828c2ecf20Sopenharmony_ci	if (f.file->f_op != &timerfd_fops) {
3838c2ecf20Sopenharmony_ci		fdput(f);
3848c2ecf20Sopenharmony_ci		return -EINVAL;
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci	*p = f;
3878c2ecf20Sopenharmony_ci	return 0;
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ciSYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	int ufd;
3938c2ecf20Sopenharmony_ci	struct timerfd_ctx *ctx;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	/* Check the TFD_* constants for consistency.  */
3968c2ecf20Sopenharmony_ci	BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC);
3978c2ecf20Sopenharmony_ci	BUILD_BUG_ON(TFD_NONBLOCK != O_NONBLOCK);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	if ((flags & ~TFD_CREATE_FLAGS) ||
4008c2ecf20Sopenharmony_ci	    (clockid != CLOCK_MONOTONIC &&
4018c2ecf20Sopenharmony_ci	     clockid != CLOCK_REALTIME &&
4028c2ecf20Sopenharmony_ci	     clockid != CLOCK_REALTIME_ALARM &&
4038c2ecf20Sopenharmony_ci	     clockid != CLOCK_BOOTTIME &&
4048c2ecf20Sopenharmony_ci	     clockid != CLOCK_BOOTTIME_ALARM))
4058c2ecf20Sopenharmony_ci		return -EINVAL;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	if ((clockid == CLOCK_REALTIME_ALARM ||
4088c2ecf20Sopenharmony_ci	     clockid == CLOCK_BOOTTIME_ALARM) &&
4098c2ecf20Sopenharmony_ci	    !capable(CAP_WAKE_ALARM))
4108c2ecf20Sopenharmony_ci		return -EPERM;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
4138c2ecf20Sopenharmony_ci	if (!ctx)
4148c2ecf20Sopenharmony_ci		return -ENOMEM;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	init_waitqueue_head(&ctx->wqh);
4178c2ecf20Sopenharmony_ci	spin_lock_init(&ctx->cancel_lock);
4188c2ecf20Sopenharmony_ci	ctx->clockid = clockid;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (isalarm(ctx))
4218c2ecf20Sopenharmony_ci		alarm_init(&ctx->t.alarm,
4228c2ecf20Sopenharmony_ci			   ctx->clockid == CLOCK_REALTIME_ALARM ?
4238c2ecf20Sopenharmony_ci			   ALARM_REALTIME : ALARM_BOOTTIME,
4248c2ecf20Sopenharmony_ci			   timerfd_alarmproc);
4258c2ecf20Sopenharmony_ci	else
4268c2ecf20Sopenharmony_ci		hrtimer_init(&ctx->t.tmr, clockid, HRTIMER_MODE_ABS);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	ctx->moffs = ktime_mono_to_real(0);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx,
4318c2ecf20Sopenharmony_ci			       O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS));
4328c2ecf20Sopenharmony_ci	if (ufd < 0)
4338c2ecf20Sopenharmony_ci		kfree(ctx);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	return ufd;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic int do_timerfd_settime(int ufd, int flags,
4398c2ecf20Sopenharmony_ci		const struct itimerspec64 *new,
4408c2ecf20Sopenharmony_ci		struct itimerspec64 *old)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	struct fd f;
4438c2ecf20Sopenharmony_ci	struct timerfd_ctx *ctx;
4448c2ecf20Sopenharmony_ci	int ret;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	if ((flags & ~TFD_SETTIME_FLAGS) ||
4478c2ecf20Sopenharmony_ci		 !itimerspec64_valid(new))
4488c2ecf20Sopenharmony_ci		return -EINVAL;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	ret = timerfd_fget(ufd, &f);
4518c2ecf20Sopenharmony_ci	if (ret)
4528c2ecf20Sopenharmony_ci		return ret;
4538c2ecf20Sopenharmony_ci	ctx = f.file->private_data;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (isalarm(ctx) && !capable(CAP_WAKE_ALARM)) {
4568c2ecf20Sopenharmony_ci		fdput(f);
4578c2ecf20Sopenharmony_ci		return -EPERM;
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	timerfd_setup_cancel(ctx, flags);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	/*
4638c2ecf20Sopenharmony_ci	 * We need to stop the existing timer before reprogramming
4648c2ecf20Sopenharmony_ci	 * it to the new values.
4658c2ecf20Sopenharmony_ci	 */
4668c2ecf20Sopenharmony_ci	for (;;) {
4678c2ecf20Sopenharmony_ci		spin_lock_irq(&ctx->wqh.lock);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci		if (isalarm(ctx)) {
4708c2ecf20Sopenharmony_ci			if (alarm_try_to_cancel(&ctx->t.alarm) >= 0)
4718c2ecf20Sopenharmony_ci				break;
4728c2ecf20Sopenharmony_ci		} else {
4738c2ecf20Sopenharmony_ci			if (hrtimer_try_to_cancel(&ctx->t.tmr) >= 0)
4748c2ecf20Sopenharmony_ci				break;
4758c2ecf20Sopenharmony_ci		}
4768c2ecf20Sopenharmony_ci		spin_unlock_irq(&ctx->wqh.lock);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		if (isalarm(ctx))
4798c2ecf20Sopenharmony_ci			hrtimer_cancel_wait_running(&ctx->t.alarm.timer);
4808c2ecf20Sopenharmony_ci		else
4818c2ecf20Sopenharmony_ci			hrtimer_cancel_wait_running(&ctx->t.tmr);
4828c2ecf20Sopenharmony_ci	}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	/*
4858c2ecf20Sopenharmony_ci	 * If the timer is expired and it's periodic, we need to advance it
4868c2ecf20Sopenharmony_ci	 * because the caller may want to know the previous expiration time.
4878c2ecf20Sopenharmony_ci	 * We do not update "ticks" and "expired" since the timer will be
4888c2ecf20Sopenharmony_ci	 * re-programmed again in the following timerfd_setup() call.
4898c2ecf20Sopenharmony_ci	 */
4908c2ecf20Sopenharmony_ci	if (ctx->expired && ctx->tintv) {
4918c2ecf20Sopenharmony_ci		if (isalarm(ctx))
4928c2ecf20Sopenharmony_ci			alarm_forward_now(&ctx->t.alarm, ctx->tintv);
4938c2ecf20Sopenharmony_ci		else
4948c2ecf20Sopenharmony_ci			hrtimer_forward_now(&ctx->t.tmr, ctx->tintv);
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	old->it_value = ktime_to_timespec64(timerfd_get_remaining(ctx));
4988c2ecf20Sopenharmony_ci	old->it_interval = ktime_to_timespec64(ctx->tintv);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	/*
5018c2ecf20Sopenharmony_ci	 * Re-program the timer to the new value ...
5028c2ecf20Sopenharmony_ci	 */
5038c2ecf20Sopenharmony_ci	ret = timerfd_setup(ctx, flags, new);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	spin_unlock_irq(&ctx->wqh.lock);
5068c2ecf20Sopenharmony_ci	fdput(f);
5078c2ecf20Sopenharmony_ci	return ret;
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic int do_timerfd_gettime(int ufd, struct itimerspec64 *t)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	struct fd f;
5138c2ecf20Sopenharmony_ci	struct timerfd_ctx *ctx;
5148c2ecf20Sopenharmony_ci	int ret = timerfd_fget(ufd, &f);
5158c2ecf20Sopenharmony_ci	if (ret)
5168c2ecf20Sopenharmony_ci		return ret;
5178c2ecf20Sopenharmony_ci	ctx = f.file->private_data;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	spin_lock_irq(&ctx->wqh.lock);
5208c2ecf20Sopenharmony_ci	if (ctx->expired && ctx->tintv) {
5218c2ecf20Sopenharmony_ci		ctx->expired = 0;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci		if (isalarm(ctx)) {
5248c2ecf20Sopenharmony_ci			ctx->ticks +=
5258c2ecf20Sopenharmony_ci				alarm_forward_now(
5268c2ecf20Sopenharmony_ci					&ctx->t.alarm, ctx->tintv) - 1;
5278c2ecf20Sopenharmony_ci			alarm_restart(&ctx->t.alarm);
5288c2ecf20Sopenharmony_ci		} else {
5298c2ecf20Sopenharmony_ci			ctx->ticks +=
5308c2ecf20Sopenharmony_ci				hrtimer_forward_now(&ctx->t.tmr, ctx->tintv)
5318c2ecf20Sopenharmony_ci				- 1;
5328c2ecf20Sopenharmony_ci			hrtimer_restart(&ctx->t.tmr);
5338c2ecf20Sopenharmony_ci		}
5348c2ecf20Sopenharmony_ci	}
5358c2ecf20Sopenharmony_ci	t->it_value = ktime_to_timespec64(timerfd_get_remaining(ctx));
5368c2ecf20Sopenharmony_ci	t->it_interval = ktime_to_timespec64(ctx->tintv);
5378c2ecf20Sopenharmony_ci	spin_unlock_irq(&ctx->wqh.lock);
5388c2ecf20Sopenharmony_ci	fdput(f);
5398c2ecf20Sopenharmony_ci	return 0;
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ciSYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
5438c2ecf20Sopenharmony_ci		const struct __kernel_itimerspec __user *, utmr,
5448c2ecf20Sopenharmony_ci		struct __kernel_itimerspec __user *, otmr)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct itimerspec64 new, old;
5478c2ecf20Sopenharmony_ci	int ret;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (get_itimerspec64(&new, utmr))
5508c2ecf20Sopenharmony_ci		return -EFAULT;
5518c2ecf20Sopenharmony_ci	ret = do_timerfd_settime(ufd, flags, &new, &old);
5528c2ecf20Sopenharmony_ci	if (ret)
5538c2ecf20Sopenharmony_ci		return ret;
5548c2ecf20Sopenharmony_ci	if (otmr && put_itimerspec64(&old, otmr))
5558c2ecf20Sopenharmony_ci		return -EFAULT;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	return ret;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ciSYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct __kernel_itimerspec __user *, otmr)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	struct itimerspec64 kotmr;
5638c2ecf20Sopenharmony_ci	int ret = do_timerfd_gettime(ufd, &kotmr);
5648c2ecf20Sopenharmony_ci	if (ret)
5658c2ecf20Sopenharmony_ci		return ret;
5668c2ecf20Sopenharmony_ci	return put_itimerspec64(&kotmr, otmr) ? -EFAULT : 0;
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT_32BIT_TIME
5708c2ecf20Sopenharmony_ciSYSCALL_DEFINE4(timerfd_settime32, int, ufd, int, flags,
5718c2ecf20Sopenharmony_ci		const struct old_itimerspec32 __user *, utmr,
5728c2ecf20Sopenharmony_ci		struct old_itimerspec32 __user *, otmr)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	struct itimerspec64 new, old;
5758c2ecf20Sopenharmony_ci	int ret;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	if (get_old_itimerspec32(&new, utmr))
5788c2ecf20Sopenharmony_ci		return -EFAULT;
5798c2ecf20Sopenharmony_ci	ret = do_timerfd_settime(ufd, flags, &new, &old);
5808c2ecf20Sopenharmony_ci	if (ret)
5818c2ecf20Sopenharmony_ci		return ret;
5828c2ecf20Sopenharmony_ci	if (otmr && put_old_itimerspec32(&old, otmr))
5838c2ecf20Sopenharmony_ci		return -EFAULT;
5848c2ecf20Sopenharmony_ci	return ret;
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ciSYSCALL_DEFINE2(timerfd_gettime32, int, ufd,
5888c2ecf20Sopenharmony_ci		struct old_itimerspec32 __user *, otmr)
5898c2ecf20Sopenharmony_ci{
5908c2ecf20Sopenharmony_ci	struct itimerspec64 kotmr;
5918c2ecf20Sopenharmony_ci	int ret = do_timerfd_gettime(ufd, &kotmr);
5928c2ecf20Sopenharmony_ci	if (ret)
5938c2ecf20Sopenharmony_ci		return ret;
5948c2ecf20Sopenharmony_ci	return put_old_itimerspec32(&kotmr, otmr) ? -EFAULT : 0;
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci#endif
597