1b215e283SDavide Libenzi /* 2b215e283SDavide Libenzi * fs/timerfd.c 3b215e283SDavide Libenzi * 4b215e283SDavide Libenzi * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org> 5b215e283SDavide Libenzi * 6b215e283SDavide Libenzi * 7b215e283SDavide Libenzi * Thanks to Thomas Gleixner for code reviews and useful comments. 8b215e283SDavide Libenzi * 9b215e283SDavide Libenzi */ 10b215e283SDavide Libenzi 1111ffa9d6STodd Poynor #include <linux/alarmtimer.h> 12b215e283SDavide Libenzi #include <linux/file.h> 13b215e283SDavide Libenzi #include <linux/poll.h> 14b215e283SDavide Libenzi #include <linux/init.h> 15b215e283SDavide Libenzi #include <linux/fs.h> 16b215e283SDavide Libenzi #include <linux/sched.h> 17b215e283SDavide Libenzi #include <linux/kernel.h> 185a0e3ad6STejun Heo #include <linux/slab.h> 19b215e283SDavide Libenzi #include <linux/list.h> 20b215e283SDavide Libenzi #include <linux/spinlock.h> 21b215e283SDavide Libenzi #include <linux/time.h> 22b215e283SDavide Libenzi #include <linux/hrtimer.h> 23b215e283SDavide Libenzi #include <linux/anon_inodes.h> 24b215e283SDavide Libenzi #include <linux/timerfd.h> 2545cc2b96SAdrian Bunk #include <linux/syscalls.h> 269d94b9e2SAl Viro #include <linux/compat.h> 279ec26907SThomas Gleixner #include <linux/rcupdate.h> 28b215e283SDavide Libenzi 29b215e283SDavide Libenzi struct timerfd_ctx { 3011ffa9d6STodd Poynor union { 31b215e283SDavide Libenzi struct hrtimer tmr; 3211ffa9d6STodd Poynor struct alarm alarm; 3311ffa9d6STodd Poynor } t; 34b215e283SDavide Libenzi ktime_t tintv; 3599ee5315SThomas Gleixner ktime_t moffs; 36b215e283SDavide Libenzi wait_queue_head_t wqh; 374d672e7aSDavide Libenzi u64 ticks; 384d672e7aSDavide Libenzi int clockid; 39af9c4957SCyrill Gorcunov short unsigned expired; 40af9c4957SCyrill Gorcunov short unsigned settime_flags; /* to show in fdinfo */ 419ec26907SThomas Gleixner struct rcu_head rcu; 429ec26907SThomas Gleixner struct list_head clist; 4399ee5315SThomas Gleixner bool might_cancel; 44b215e283SDavide Libenzi }; 45b215e283SDavide Libenzi 469ec26907SThomas Gleixner static LIST_HEAD(cancel_list); 479ec26907SThomas Gleixner static DEFINE_SPINLOCK(cancel_lock); 489ec26907SThomas Gleixner 4911ffa9d6STodd Poynor static inline bool isalarm(struct timerfd_ctx *ctx) 5011ffa9d6STodd Poynor { 5111ffa9d6STodd Poynor return ctx->clockid == CLOCK_REALTIME_ALARM || 5211ffa9d6STodd Poynor ctx->clockid == CLOCK_BOOTTIME_ALARM; 5311ffa9d6STodd Poynor } 5411ffa9d6STodd Poynor 55b215e283SDavide Libenzi /* 56b215e283SDavide Libenzi * This gets called when the timer event triggers. We set the "expired" 57b215e283SDavide Libenzi * flag, but we do not re-arm the timer (in case it's necessary, 584d672e7aSDavide Libenzi * tintv.tv64 != 0) until the timer is accessed. 59b215e283SDavide Libenzi */ 6011ffa9d6STodd Poynor static void timerfd_triggered(struct timerfd_ctx *ctx) 61b215e283SDavide Libenzi { 62b215e283SDavide Libenzi unsigned long flags; 63b215e283SDavide Libenzi 6418963c01SDavide Libenzi spin_lock_irqsave(&ctx->wqh.lock, flags); 65b215e283SDavide Libenzi ctx->expired = 1; 664d672e7aSDavide Libenzi ctx->ticks++; 67b215e283SDavide Libenzi wake_up_locked(&ctx->wqh); 6818963c01SDavide Libenzi spin_unlock_irqrestore(&ctx->wqh.lock, flags); 6911ffa9d6STodd Poynor } 70b215e283SDavide Libenzi 7111ffa9d6STodd Poynor static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr) 7211ffa9d6STodd Poynor { 7311ffa9d6STodd Poynor struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, 7411ffa9d6STodd Poynor t.tmr); 7511ffa9d6STodd Poynor timerfd_triggered(ctx); 76b215e283SDavide Libenzi return HRTIMER_NORESTART; 77b215e283SDavide Libenzi } 78b215e283SDavide Libenzi 7911ffa9d6STodd Poynor static enum alarmtimer_restart timerfd_alarmproc(struct alarm *alarm, 8011ffa9d6STodd Poynor ktime_t now) 8111ffa9d6STodd Poynor { 8211ffa9d6STodd Poynor struct timerfd_ctx *ctx = container_of(alarm, struct timerfd_ctx, 8311ffa9d6STodd Poynor t.alarm); 8411ffa9d6STodd Poynor timerfd_triggered(ctx); 8511ffa9d6STodd Poynor return ALARMTIMER_NORESTART; 8611ffa9d6STodd Poynor } 8711ffa9d6STodd Poynor 889ec26907SThomas Gleixner /* 899ec26907SThomas Gleixner * Called when the clock was set to cancel the timers in the cancel 901123d939SMax Asbock * list. This will wake up processes waiting on these timers. The 911123d939SMax Asbock * wake-up requires ctx->ticks to be non zero, therefore we increment 921123d939SMax Asbock * it before calling wake_up_locked(). 939ec26907SThomas Gleixner */ 949ec26907SThomas Gleixner void timerfd_clock_was_set(void) 959ec26907SThomas Gleixner { 9653cc7badSThomas Gleixner ktime_t moffs = ktime_mono_to_real((ktime_t){ .tv64 = 0 }); 979ec26907SThomas Gleixner struct timerfd_ctx *ctx; 989ec26907SThomas Gleixner unsigned long flags; 999ec26907SThomas Gleixner 1009ec26907SThomas Gleixner rcu_read_lock(); 1019ec26907SThomas Gleixner list_for_each_entry_rcu(ctx, &cancel_list, clist) { 1029ec26907SThomas Gleixner if (!ctx->might_cancel) 1039ec26907SThomas Gleixner continue; 1049ec26907SThomas Gleixner spin_lock_irqsave(&ctx->wqh.lock, flags); 1059ec26907SThomas Gleixner if (ctx->moffs.tv64 != moffs.tv64) { 1069ec26907SThomas Gleixner ctx->moffs.tv64 = KTIME_MAX; 1071123d939SMax Asbock ctx->ticks++; 1089ec26907SThomas Gleixner wake_up_locked(&ctx->wqh); 1099ec26907SThomas Gleixner } 1109ec26907SThomas Gleixner spin_unlock_irqrestore(&ctx->wqh.lock, flags); 1119ec26907SThomas Gleixner } 1129ec26907SThomas Gleixner rcu_read_unlock(); 1139ec26907SThomas Gleixner } 1149ec26907SThomas Gleixner 1159ec26907SThomas Gleixner static void timerfd_remove_cancel(struct timerfd_ctx *ctx) 1169ec26907SThomas Gleixner { 1179ec26907SThomas Gleixner if (ctx->might_cancel) { 1189ec26907SThomas Gleixner ctx->might_cancel = false; 1199ec26907SThomas Gleixner spin_lock(&cancel_lock); 1209ec26907SThomas Gleixner list_del_rcu(&ctx->clist); 1219ec26907SThomas Gleixner spin_unlock(&cancel_lock); 1229ec26907SThomas Gleixner } 1239ec26907SThomas Gleixner } 1249ec26907SThomas Gleixner 1259ec26907SThomas Gleixner static bool timerfd_canceled(struct timerfd_ctx *ctx) 1269ec26907SThomas Gleixner { 1279ec26907SThomas Gleixner if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX) 1289ec26907SThomas Gleixner return false; 12953cc7badSThomas Gleixner ctx->moffs = ktime_mono_to_real((ktime_t){ .tv64 = 0 }); 1309ec26907SThomas Gleixner return true; 1319ec26907SThomas Gleixner } 1329ec26907SThomas Gleixner 1339ec26907SThomas Gleixner static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags) 1349ec26907SThomas Gleixner { 13511ffa9d6STodd Poynor if ((ctx->clockid == CLOCK_REALTIME || 13611ffa9d6STodd Poynor ctx->clockid == CLOCK_REALTIME_ALARM) && 13711ffa9d6STodd Poynor (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) { 1389ec26907SThomas Gleixner if (!ctx->might_cancel) { 1399ec26907SThomas Gleixner ctx->might_cancel = true; 1409ec26907SThomas Gleixner spin_lock(&cancel_lock); 1419ec26907SThomas Gleixner list_add_rcu(&ctx->clist, &cancel_list); 1429ec26907SThomas Gleixner spin_unlock(&cancel_lock); 1439ec26907SThomas Gleixner } 1449ec26907SThomas Gleixner } else if (ctx->might_cancel) { 1459ec26907SThomas Gleixner timerfd_remove_cancel(ctx); 1469ec26907SThomas Gleixner } 1479ec26907SThomas Gleixner } 1489ec26907SThomas Gleixner 1494d672e7aSDavide Libenzi static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx) 1504d672e7aSDavide Libenzi { 15176369470SArjan van de Ven ktime_t remaining; 1524d672e7aSDavide Libenzi 15311ffa9d6STodd Poynor if (isalarm(ctx)) 15411ffa9d6STodd Poynor remaining = alarm_expires_remaining(&ctx->t.alarm); 15511ffa9d6STodd Poynor else 15611ffa9d6STodd Poynor remaining = hrtimer_expires_remaining(&ctx->t.tmr); 15711ffa9d6STodd Poynor 1584d672e7aSDavide Libenzi return remaining.tv64 < 0 ? ktime_set(0, 0): remaining; 1594d672e7aSDavide Libenzi } 1604d672e7aSDavide Libenzi 16199ee5315SThomas Gleixner static int timerfd_setup(struct timerfd_ctx *ctx, int flags, 162b215e283SDavide Libenzi const struct itimerspec *ktmr) 163b215e283SDavide Libenzi { 164b215e283SDavide Libenzi enum hrtimer_mode htmode; 165b215e283SDavide Libenzi ktime_t texp; 16699ee5315SThomas Gleixner int clockid = ctx->clockid; 167b215e283SDavide Libenzi 168b215e283SDavide Libenzi htmode = (flags & TFD_TIMER_ABSTIME) ? 169b215e283SDavide Libenzi HRTIMER_MODE_ABS: HRTIMER_MODE_REL; 170b215e283SDavide Libenzi 171b215e283SDavide Libenzi texp = timespec_to_ktime(ktmr->it_value); 172b215e283SDavide Libenzi ctx->expired = 0; 1734d672e7aSDavide Libenzi ctx->ticks = 0; 174b215e283SDavide Libenzi ctx->tintv = timespec_to_ktime(ktmr->it_interval); 17511ffa9d6STodd Poynor 17611ffa9d6STodd Poynor if (isalarm(ctx)) { 17711ffa9d6STodd Poynor alarm_init(&ctx->t.alarm, 17811ffa9d6STodd Poynor ctx->clockid == CLOCK_REALTIME_ALARM ? 17911ffa9d6STodd Poynor ALARM_REALTIME : ALARM_BOOTTIME, 18011ffa9d6STodd Poynor timerfd_alarmproc); 18111ffa9d6STodd Poynor } else { 18211ffa9d6STodd Poynor hrtimer_init(&ctx->t.tmr, clockid, htmode); 18311ffa9d6STodd Poynor hrtimer_set_expires(&ctx->t.tmr, texp); 18411ffa9d6STodd Poynor ctx->t.tmr.function = timerfd_tmrproc; 18511ffa9d6STodd Poynor } 18611ffa9d6STodd Poynor 18799ee5315SThomas Gleixner if (texp.tv64 != 0) { 18811ffa9d6STodd Poynor if (isalarm(ctx)) { 18911ffa9d6STodd Poynor if (flags & TFD_TIMER_ABSTIME) 19011ffa9d6STodd Poynor alarm_start(&ctx->t.alarm, texp); 19111ffa9d6STodd Poynor else 19211ffa9d6STodd Poynor alarm_start_relative(&ctx->t.alarm, texp); 19311ffa9d6STodd Poynor } else { 19411ffa9d6STodd Poynor hrtimer_start(&ctx->t.tmr, texp, htmode); 19511ffa9d6STodd Poynor } 19611ffa9d6STodd Poynor 19799ee5315SThomas Gleixner if (timerfd_canceled(ctx)) 19899ee5315SThomas Gleixner return -ECANCELED; 19999ee5315SThomas Gleixner } 200af9c4957SCyrill Gorcunov 201af9c4957SCyrill Gorcunov ctx->settime_flags = flags & TFD_SETTIME_FLAGS; 20299ee5315SThomas Gleixner return 0; 203b215e283SDavide Libenzi } 204b215e283SDavide Libenzi 205b215e283SDavide Libenzi static int timerfd_release(struct inode *inode, struct file *file) 206b215e283SDavide Libenzi { 207b215e283SDavide Libenzi struct timerfd_ctx *ctx = file->private_data; 208b215e283SDavide Libenzi 2099ec26907SThomas Gleixner timerfd_remove_cancel(ctx); 21011ffa9d6STodd Poynor 21111ffa9d6STodd Poynor if (isalarm(ctx)) 21211ffa9d6STodd Poynor alarm_cancel(&ctx->t.alarm); 21311ffa9d6STodd Poynor else 21411ffa9d6STodd Poynor hrtimer_cancel(&ctx->t.tmr); 2159ec26907SThomas Gleixner kfree_rcu(ctx, rcu); 216b215e283SDavide Libenzi return 0; 217b215e283SDavide Libenzi } 218b215e283SDavide Libenzi 219b215e283SDavide Libenzi static unsigned int timerfd_poll(struct file *file, poll_table *wait) 220b215e283SDavide Libenzi { 221b215e283SDavide Libenzi struct timerfd_ctx *ctx = file->private_data; 222b215e283SDavide Libenzi unsigned int events = 0; 223b215e283SDavide Libenzi unsigned long flags; 224b215e283SDavide Libenzi 225b215e283SDavide Libenzi poll_wait(file, &ctx->wqh, wait); 226b215e283SDavide Libenzi 22718963c01SDavide Libenzi spin_lock_irqsave(&ctx->wqh.lock, flags); 2284d672e7aSDavide Libenzi if (ctx->ticks) 229b215e283SDavide Libenzi events |= POLLIN; 23018963c01SDavide Libenzi spin_unlock_irqrestore(&ctx->wqh.lock, flags); 231b215e283SDavide Libenzi 232b215e283SDavide Libenzi return events; 233b215e283SDavide Libenzi } 234b215e283SDavide Libenzi 235b215e283SDavide Libenzi static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count, 236b215e283SDavide Libenzi loff_t *ppos) 237b215e283SDavide Libenzi { 238b215e283SDavide Libenzi struct timerfd_ctx *ctx = file->private_data; 239b215e283SDavide Libenzi ssize_t res; 24009828402SDavide Libenzi u64 ticks = 0; 241b215e283SDavide Libenzi 242b215e283SDavide Libenzi if (count < sizeof(ticks)) 243b215e283SDavide Libenzi return -EINVAL; 24418963c01SDavide Libenzi spin_lock_irq(&ctx->wqh.lock); 2458120a8aaSMichal Nazarewicz if (file->f_flags & O_NONBLOCK) 246b215e283SDavide Libenzi res = -EAGAIN; 2478120a8aaSMichal Nazarewicz else 2488120a8aaSMichal Nazarewicz res = wait_event_interruptible_locked_irq(ctx->wqh, ctx->ticks); 24999ee5315SThomas Gleixner 25099ee5315SThomas Gleixner /* 25199ee5315SThomas Gleixner * If clock has changed, we do not care about the 25299ee5315SThomas Gleixner * ticks and we do not rearm the timer. Userspace must 25399ee5315SThomas Gleixner * reevaluate anyway. 25499ee5315SThomas Gleixner */ 25599ee5315SThomas Gleixner if (timerfd_canceled(ctx)) { 2569ec26907SThomas Gleixner ctx->ticks = 0; 25799ee5315SThomas Gleixner ctx->expired = 0; 25899ee5315SThomas Gleixner res = -ECANCELED; 25999ee5315SThomas Gleixner } 26099ee5315SThomas Gleixner 2619ec26907SThomas Gleixner if (ctx->ticks) { 2629ec26907SThomas Gleixner ticks = ctx->ticks; 2639ec26907SThomas Gleixner 2644d672e7aSDavide Libenzi if (ctx->expired && ctx->tintv.tv64) { 265b215e283SDavide Libenzi /* 266b215e283SDavide Libenzi * If tintv.tv64 != 0, this is a periodic timer that 267b215e283SDavide Libenzi * needs to be re-armed. We avoid doing it in the timer 268b215e283SDavide Libenzi * callback to avoid DoS attacks specifying a very 269b215e283SDavide Libenzi * short timer period. 270b215e283SDavide Libenzi */ 27111ffa9d6STodd Poynor if (isalarm(ctx)) { 27211ffa9d6STodd Poynor ticks += alarm_forward_now( 27311ffa9d6STodd Poynor &ctx->t.alarm, ctx->tintv) - 1; 27411ffa9d6STodd Poynor alarm_restart(&ctx->t.alarm); 27511ffa9d6STodd Poynor } else { 27611ffa9d6STodd Poynor ticks += hrtimer_forward_now(&ctx->t.tmr, 2774d672e7aSDavide Libenzi ctx->tintv) - 1; 27811ffa9d6STodd Poynor hrtimer_restart(&ctx->t.tmr); 27911ffa9d6STodd Poynor } 2804d672e7aSDavide Libenzi } 2814d672e7aSDavide Libenzi ctx->expired = 0; 2824d672e7aSDavide Libenzi ctx->ticks = 0; 283b215e283SDavide Libenzi } 28418963c01SDavide Libenzi spin_unlock_irq(&ctx->wqh.lock); 285b215e283SDavide Libenzi if (ticks) 28609828402SDavide Libenzi res = put_user(ticks, (u64 __user *) buf) ? -EFAULT: sizeof(ticks); 287b215e283SDavide Libenzi return res; 288b215e283SDavide Libenzi } 289b215e283SDavide Libenzi 290af9c4957SCyrill Gorcunov #ifdef CONFIG_PROC_FS 291*a3816ab0SJoe Perches static void timerfd_show(struct seq_file *m, struct file *file) 292af9c4957SCyrill Gorcunov { 293af9c4957SCyrill Gorcunov struct timerfd_ctx *ctx = file->private_data; 294af9c4957SCyrill Gorcunov struct itimerspec t; 295af9c4957SCyrill Gorcunov 296af9c4957SCyrill Gorcunov spin_lock_irq(&ctx->wqh.lock); 297af9c4957SCyrill Gorcunov t.it_value = ktime_to_timespec(timerfd_get_remaining(ctx)); 298af9c4957SCyrill Gorcunov t.it_interval = ktime_to_timespec(ctx->tintv); 299af9c4957SCyrill Gorcunov spin_unlock_irq(&ctx->wqh.lock); 300af9c4957SCyrill Gorcunov 301*a3816ab0SJoe Perches seq_printf(m, 302af9c4957SCyrill Gorcunov "clockid: %d\n" 303af9c4957SCyrill Gorcunov "ticks: %llu\n" 304af9c4957SCyrill Gorcunov "settime flags: 0%o\n" 305af9c4957SCyrill Gorcunov "it_value: (%llu, %llu)\n" 306af9c4957SCyrill Gorcunov "it_interval: (%llu, %llu)\n", 307*a3816ab0SJoe Perches ctx->clockid, 308*a3816ab0SJoe Perches (unsigned long long)ctx->ticks, 309af9c4957SCyrill Gorcunov ctx->settime_flags, 310af9c4957SCyrill Gorcunov (unsigned long long)t.it_value.tv_sec, 311af9c4957SCyrill Gorcunov (unsigned long long)t.it_value.tv_nsec, 312af9c4957SCyrill Gorcunov (unsigned long long)t.it_interval.tv_sec, 313af9c4957SCyrill Gorcunov (unsigned long long)t.it_interval.tv_nsec); 314af9c4957SCyrill Gorcunov } 315af9c4957SCyrill Gorcunov #else 316af9c4957SCyrill Gorcunov #define timerfd_show NULL 317af9c4957SCyrill Gorcunov #endif 318af9c4957SCyrill Gorcunov 3195442e9fbSCyrill Gorcunov #ifdef CONFIG_CHECKPOINT_RESTORE 3205442e9fbSCyrill Gorcunov static long timerfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 3215442e9fbSCyrill Gorcunov { 3225442e9fbSCyrill Gorcunov struct timerfd_ctx *ctx = file->private_data; 3235442e9fbSCyrill Gorcunov int ret = 0; 3245442e9fbSCyrill Gorcunov 3255442e9fbSCyrill Gorcunov switch (cmd) { 3265442e9fbSCyrill Gorcunov case TFD_IOC_SET_TICKS: { 3275442e9fbSCyrill Gorcunov u64 ticks; 3285442e9fbSCyrill Gorcunov 3295442e9fbSCyrill Gorcunov if (copy_from_user(&ticks, (u64 __user *)arg, sizeof(ticks))) 3305442e9fbSCyrill Gorcunov return -EFAULT; 3315442e9fbSCyrill Gorcunov if (!ticks) 3325442e9fbSCyrill Gorcunov return -EINVAL; 3335442e9fbSCyrill Gorcunov 3345442e9fbSCyrill Gorcunov spin_lock_irq(&ctx->wqh.lock); 3355442e9fbSCyrill Gorcunov if (!timerfd_canceled(ctx)) { 3365442e9fbSCyrill Gorcunov ctx->ticks = ticks; 3375442e9fbSCyrill Gorcunov wake_up_locked(&ctx->wqh); 3385442e9fbSCyrill Gorcunov } else 3395442e9fbSCyrill Gorcunov ret = -ECANCELED; 3405442e9fbSCyrill Gorcunov spin_unlock_irq(&ctx->wqh.lock); 3415442e9fbSCyrill Gorcunov break; 3425442e9fbSCyrill Gorcunov } 3435442e9fbSCyrill Gorcunov default: 3445442e9fbSCyrill Gorcunov ret = -ENOTTY; 3455442e9fbSCyrill Gorcunov break; 3465442e9fbSCyrill Gorcunov } 3475442e9fbSCyrill Gorcunov 3485442e9fbSCyrill Gorcunov return ret; 3495442e9fbSCyrill Gorcunov } 3505442e9fbSCyrill Gorcunov #else 3515442e9fbSCyrill Gorcunov #define timerfd_ioctl NULL 3525442e9fbSCyrill Gorcunov #endif 3535442e9fbSCyrill Gorcunov 354b215e283SDavide Libenzi static const struct file_operations timerfd_fops = { 355b215e283SDavide Libenzi .release = timerfd_release, 356b215e283SDavide Libenzi .poll = timerfd_poll, 357b215e283SDavide Libenzi .read = timerfd_read, 3586038f373SArnd Bergmann .llseek = noop_llseek, 359af9c4957SCyrill Gorcunov .show_fdinfo = timerfd_show, 3605442e9fbSCyrill Gorcunov .unlocked_ioctl = timerfd_ioctl, 361b215e283SDavide Libenzi }; 362b215e283SDavide Libenzi 3632903ff01SAl Viro static int timerfd_fget(int fd, struct fd *p) 364b215e283SDavide Libenzi { 3652903ff01SAl Viro struct fd f = fdget(fd); 3662903ff01SAl Viro if (!f.file) 3672903ff01SAl Viro return -EBADF; 3682903ff01SAl Viro if (f.file->f_op != &timerfd_fops) { 3692903ff01SAl Viro fdput(f); 3702903ff01SAl Viro return -EINVAL; 3714d672e7aSDavide Libenzi } 3722903ff01SAl Viro *p = f; 3732903ff01SAl Viro return 0; 3744d672e7aSDavide Libenzi } 3754d672e7aSDavide Libenzi 376836f92adSHeiko Carstens SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) 3774d672e7aSDavide Libenzi { 3782030a42cSAl Viro int ufd; 379b215e283SDavide Libenzi struct timerfd_ctx *ctx; 380b215e283SDavide Libenzi 381e38b36f3SUlrich Drepper /* Check the TFD_* constants for consistency. */ 382e38b36f3SUlrich Drepper BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC); 383e38b36f3SUlrich Drepper BUILD_BUG_ON(TFD_NONBLOCK != O_NONBLOCK); 384e38b36f3SUlrich Drepper 385610d18f4SDavide Libenzi if ((flags & ~TFD_CREATE_FLAGS) || 386610d18f4SDavide Libenzi (clockid != CLOCK_MONOTONIC && 38711ffa9d6STodd Poynor clockid != CLOCK_REALTIME && 38811ffa9d6STodd Poynor clockid != CLOCK_REALTIME_ALARM && 3894a2378a9SGreg Hackmann clockid != CLOCK_BOOTTIME && 39011ffa9d6STodd Poynor clockid != CLOCK_BOOTTIME_ALARM)) 391b215e283SDavide Libenzi return -EINVAL; 392b215e283SDavide Libenzi 3934d672e7aSDavide Libenzi ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 394b215e283SDavide Libenzi if (!ctx) 395b215e283SDavide Libenzi return -ENOMEM; 396b215e283SDavide Libenzi 397b215e283SDavide Libenzi init_waitqueue_head(&ctx->wqh); 3984d672e7aSDavide Libenzi ctx->clockid = clockid; 39911ffa9d6STodd Poynor 40011ffa9d6STodd Poynor if (isalarm(ctx)) 40111ffa9d6STodd Poynor alarm_init(&ctx->t.alarm, 40211ffa9d6STodd Poynor ctx->clockid == CLOCK_REALTIME_ALARM ? 40311ffa9d6STodd Poynor ALARM_REALTIME : ALARM_BOOTTIME, 40411ffa9d6STodd Poynor timerfd_alarmproc); 40511ffa9d6STodd Poynor else 40611ffa9d6STodd Poynor hrtimer_init(&ctx->t.tmr, clockid, HRTIMER_MODE_ABS); 40711ffa9d6STodd Poynor 40853cc7badSThomas Gleixner ctx->moffs = ktime_mono_to_real((ktime_t){ .tv64 = 0 }); 409b215e283SDavide Libenzi 41011fcb6c1SUlrich Drepper ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx, 411628ff7c1SRoland Dreier O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS)); 4122030a42cSAl Viro if (ufd < 0) 4134d672e7aSDavide Libenzi kfree(ctx); 4144d672e7aSDavide Libenzi 4154d672e7aSDavide Libenzi return ufd; 4164d672e7aSDavide Libenzi } 4174d672e7aSDavide Libenzi 4189d94b9e2SAl Viro static int do_timerfd_settime(int ufd, int flags, 4199d94b9e2SAl Viro const struct itimerspec *new, 4209d94b9e2SAl Viro struct itimerspec *old) 4214d672e7aSDavide Libenzi { 4222903ff01SAl Viro struct fd f; 4234d672e7aSDavide Libenzi struct timerfd_ctx *ctx; 4242903ff01SAl Viro int ret; 4254d672e7aSDavide Libenzi 426610d18f4SDavide Libenzi if ((flags & ~TFD_SETTIME_FLAGS) || 4279d94b9e2SAl Viro !timespec_valid(&new->it_value) || 4289d94b9e2SAl Viro !timespec_valid(&new->it_interval)) 4294d672e7aSDavide Libenzi return -EINVAL; 4304d672e7aSDavide Libenzi 4312903ff01SAl Viro ret = timerfd_fget(ufd, &f); 4322903ff01SAl Viro if (ret) 4332903ff01SAl Viro return ret; 4342903ff01SAl Viro ctx = f.file->private_data; 4354d672e7aSDavide Libenzi 4369ec26907SThomas Gleixner timerfd_setup_cancel(ctx, flags); 4379ec26907SThomas Gleixner 438b215e283SDavide Libenzi /* 439b215e283SDavide Libenzi * We need to stop the existing timer before reprogramming 440b215e283SDavide Libenzi * it to the new values. 441b215e283SDavide Libenzi */ 442b215e283SDavide Libenzi for (;;) { 44318963c01SDavide Libenzi spin_lock_irq(&ctx->wqh.lock); 44411ffa9d6STodd Poynor 44511ffa9d6STodd Poynor if (isalarm(ctx)) { 44611ffa9d6STodd Poynor if (alarm_try_to_cancel(&ctx->t.alarm) >= 0) 447b215e283SDavide Libenzi break; 44811ffa9d6STodd Poynor } else { 44911ffa9d6STodd Poynor if (hrtimer_try_to_cancel(&ctx->t.tmr) >= 0) 45011ffa9d6STodd Poynor break; 45111ffa9d6STodd Poynor } 45218963c01SDavide Libenzi spin_unlock_irq(&ctx->wqh.lock); 453b215e283SDavide Libenzi cpu_relax(); 454b215e283SDavide Libenzi } 4554d672e7aSDavide Libenzi 4564d672e7aSDavide Libenzi /* 4574d672e7aSDavide Libenzi * If the timer is expired and it's periodic, we need to advance it 4584d672e7aSDavide Libenzi * because the caller may want to know the previous expiration time. 4594d672e7aSDavide Libenzi * We do not update "ticks" and "expired" since the timer will be 4604d672e7aSDavide Libenzi * re-programmed again in the following timerfd_setup() call. 4614d672e7aSDavide Libenzi */ 46211ffa9d6STodd Poynor if (ctx->expired && ctx->tintv.tv64) { 46311ffa9d6STodd Poynor if (isalarm(ctx)) 46411ffa9d6STodd Poynor alarm_forward_now(&ctx->t.alarm, ctx->tintv); 46511ffa9d6STodd Poynor else 46611ffa9d6STodd Poynor hrtimer_forward_now(&ctx->t.tmr, ctx->tintv); 46711ffa9d6STodd Poynor } 4684d672e7aSDavide Libenzi 4699d94b9e2SAl Viro old->it_value = ktime_to_timespec(timerfd_get_remaining(ctx)); 4709d94b9e2SAl Viro old->it_interval = ktime_to_timespec(ctx->tintv); 4714d672e7aSDavide Libenzi 472b215e283SDavide Libenzi /* 473b215e283SDavide Libenzi * Re-program the timer to the new value ... 474b215e283SDavide Libenzi */ 4759d94b9e2SAl Viro ret = timerfd_setup(ctx, flags, new); 476b215e283SDavide Libenzi 47718963c01SDavide Libenzi spin_unlock_irq(&ctx->wqh.lock); 4782903ff01SAl Viro fdput(f); 47999ee5315SThomas Gleixner return ret; 480b215e283SDavide Libenzi } 481b215e283SDavide Libenzi 4829d94b9e2SAl Viro static int do_timerfd_gettime(int ufd, struct itimerspec *t) 4834d672e7aSDavide Libenzi { 4842903ff01SAl Viro struct fd f; 4854d672e7aSDavide Libenzi struct timerfd_ctx *ctx; 4862903ff01SAl Viro int ret = timerfd_fget(ufd, &f); 4872903ff01SAl Viro if (ret) 4882903ff01SAl Viro return ret; 4892903ff01SAl Viro ctx = f.file->private_data; 4904d672e7aSDavide Libenzi 4914d672e7aSDavide Libenzi spin_lock_irq(&ctx->wqh.lock); 4924d672e7aSDavide Libenzi if (ctx->expired && ctx->tintv.tv64) { 4934d672e7aSDavide Libenzi ctx->expired = 0; 49411ffa9d6STodd Poynor 49511ffa9d6STodd Poynor if (isalarm(ctx)) { 4964d672e7aSDavide Libenzi ctx->ticks += 49711ffa9d6STodd Poynor alarm_forward_now( 49811ffa9d6STodd Poynor &ctx->t.alarm, ctx->tintv) - 1; 49911ffa9d6STodd Poynor alarm_restart(&ctx->t.alarm); 50011ffa9d6STodd Poynor } else { 50111ffa9d6STodd Poynor ctx->ticks += 50211ffa9d6STodd Poynor hrtimer_forward_now(&ctx->t.tmr, ctx->tintv) 50311ffa9d6STodd Poynor - 1; 50411ffa9d6STodd Poynor hrtimer_restart(&ctx->t.tmr); 50511ffa9d6STodd Poynor } 5064d672e7aSDavide Libenzi } 5079d94b9e2SAl Viro t->it_value = ktime_to_timespec(timerfd_get_remaining(ctx)); 5089d94b9e2SAl Viro t->it_interval = ktime_to_timespec(ctx->tintv); 5094d672e7aSDavide Libenzi spin_unlock_irq(&ctx->wqh.lock); 5102903ff01SAl Viro fdput(f); 5119d94b9e2SAl Viro return 0; 5129d94b9e2SAl Viro } 5134d672e7aSDavide Libenzi 5149d94b9e2SAl Viro SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, 5159d94b9e2SAl Viro const struct itimerspec __user *, utmr, 5169d94b9e2SAl Viro struct itimerspec __user *, otmr) 5179d94b9e2SAl Viro { 5189d94b9e2SAl Viro struct itimerspec new, old; 5199d94b9e2SAl Viro int ret; 5209d94b9e2SAl Viro 5219d94b9e2SAl Viro if (copy_from_user(&new, utmr, sizeof(new))) 5229d94b9e2SAl Viro return -EFAULT; 5239d94b9e2SAl Viro ret = do_timerfd_settime(ufd, flags, &new, &old); 5249d94b9e2SAl Viro if (ret) 5259d94b9e2SAl Viro return ret; 5269d94b9e2SAl Viro if (otmr && copy_to_user(otmr, &old, sizeof(old))) 5279d94b9e2SAl Viro return -EFAULT; 5289d94b9e2SAl Viro 5299d94b9e2SAl Viro return ret; 5309d94b9e2SAl Viro } 5319d94b9e2SAl Viro 5329d94b9e2SAl Viro SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr) 5339d94b9e2SAl Viro { 5349d94b9e2SAl Viro struct itimerspec kotmr; 5359d94b9e2SAl Viro int ret = do_timerfd_gettime(ufd, &kotmr); 5369d94b9e2SAl Viro if (ret) 5379d94b9e2SAl Viro return ret; 5384d672e7aSDavide Libenzi return copy_to_user(otmr, &kotmr, sizeof(kotmr)) ? -EFAULT: 0; 539b215e283SDavide Libenzi } 540b215e283SDavide Libenzi 5410e803bafSHeiko Carstens #ifdef CONFIG_COMPAT 5429d94b9e2SAl Viro COMPAT_SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, 5430e803bafSHeiko Carstens const struct compat_itimerspec __user *, utmr, 5440e803bafSHeiko Carstens struct compat_itimerspec __user *, otmr) 5459d94b9e2SAl Viro { 5469d94b9e2SAl Viro struct itimerspec new, old; 5479d94b9e2SAl Viro int ret; 5489d94b9e2SAl Viro 5499d94b9e2SAl Viro if (get_compat_itimerspec(&new, utmr)) 5509d94b9e2SAl Viro return -EFAULT; 5519d94b9e2SAl Viro ret = do_timerfd_settime(ufd, flags, &new, &old); 5529d94b9e2SAl Viro if (ret) 5539d94b9e2SAl Viro return ret; 5549d94b9e2SAl Viro if (otmr && put_compat_itimerspec(otmr, &old)) 5559d94b9e2SAl Viro return -EFAULT; 5569d94b9e2SAl Viro return ret; 5579d94b9e2SAl Viro } 5589d94b9e2SAl Viro 5599d94b9e2SAl Viro COMPAT_SYSCALL_DEFINE2(timerfd_gettime, int, ufd, 5600e803bafSHeiko Carstens struct compat_itimerspec __user *, otmr) 5619d94b9e2SAl Viro { 5629d94b9e2SAl Viro struct itimerspec kotmr; 5639d94b9e2SAl Viro int ret = do_timerfd_gettime(ufd, &kotmr); 5649d94b9e2SAl Viro if (ret) 5659d94b9e2SAl Viro return ret; 5660e803bafSHeiko Carstens return put_compat_itimerspec(otmr, &kotmr) ? -EFAULT: 0; 5679d94b9e2SAl Viro } 5689d94b9e2SAl Viro #endif 569