LCOV - code coverage report
Current view: top level - fs - timerfd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 226 0.0 %
Date: 2023-08-24 13:40:31 Functions: 0 22 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  *  fs/timerfd.c
       4             :  *
       5             :  *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
       6             :  *
       7             :  *
       8             :  *  Thanks to Thomas Gleixner for code reviews and useful comments.
       9             :  *
      10             :  */
      11             : 
      12             : #include <linux/alarmtimer.h>
      13             : #include <linux/file.h>
      14             : #include <linux/poll.h>
      15             : #include <linux/init.h>
      16             : #include <linux/fs.h>
      17             : #include <linux/sched.h>
      18             : #include <linux/kernel.h>
      19             : #include <linux/slab.h>
      20             : #include <linux/list.h>
      21             : #include <linux/spinlock.h>
      22             : #include <linux/time.h>
      23             : #include <linux/hrtimer.h>
      24             : #include <linux/anon_inodes.h>
      25             : #include <linux/timerfd.h>
      26             : #include <linux/syscalls.h>
      27             : #include <linux/compat.h>
      28             : #include <linux/rcupdate.h>
      29             : #include <linux/time_namespace.h>
      30             : 
      31             : struct timerfd_ctx {
      32             :         union {
      33             :                 struct hrtimer tmr;
      34             :                 struct alarm alarm;
      35             :         } t;
      36             :         ktime_t tintv;
      37             :         ktime_t moffs;
      38             :         wait_queue_head_t wqh;
      39             :         u64 ticks;
      40             :         int clockid;
      41             :         short unsigned expired;
      42             :         short unsigned settime_flags;   /* to show in fdinfo */
      43             :         struct rcu_head rcu;
      44             :         struct list_head clist;
      45             :         spinlock_t cancel_lock;
      46             :         bool might_cancel;
      47             : };
      48             : 
      49             : static LIST_HEAD(cancel_list);
      50             : static DEFINE_SPINLOCK(cancel_lock);
      51             : 
      52             : static inline bool isalarm(struct timerfd_ctx *ctx)
      53             : {
      54           0 :         return ctx->clockid == CLOCK_REALTIME_ALARM ||
      55             :                 ctx->clockid == CLOCK_BOOTTIME_ALARM;
      56             : }
      57             : 
      58             : /*
      59             :  * This gets called when the timer event triggers. We set the "expired"
      60             :  * flag, but we do not re-arm the timer (in case it's necessary,
      61             :  * tintv != 0) until the timer is accessed.
      62             :  */
      63           0 : static void timerfd_triggered(struct timerfd_ctx *ctx)
      64             : {
      65             :         unsigned long flags;
      66             : 
      67           0 :         spin_lock_irqsave(&ctx->wqh.lock, flags);
      68           0 :         ctx->expired = 1;
      69           0 :         ctx->ticks++;
      70           0 :         wake_up_locked_poll(&ctx->wqh, EPOLLIN);
      71           0 :         spin_unlock_irqrestore(&ctx->wqh.lock, flags);
      72           0 : }
      73             : 
      74           0 : static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
      75             : {
      76           0 :         struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx,
      77             :                                                t.tmr);
      78           0 :         timerfd_triggered(ctx);
      79           0 :         return HRTIMER_NORESTART;
      80             : }
      81             : 
      82           0 : static enum alarmtimer_restart timerfd_alarmproc(struct alarm *alarm,
      83             :         ktime_t now)
      84             : {
      85           0 :         struct timerfd_ctx *ctx = container_of(alarm, struct timerfd_ctx,
      86             :                                                t.alarm);
      87           0 :         timerfd_triggered(ctx);
      88           0 :         return ALARMTIMER_NORESTART;
      89             : }
      90             : 
      91             : /*
      92             :  * Called when the clock was set to cancel the timers in the cancel
      93             :  * list. This will wake up processes waiting on these timers. The
      94             :  * wake-up requires ctx->ticks to be non zero, therefore we increment
      95             :  * it before calling wake_up_locked().
      96             :  */
      97           0 : void timerfd_clock_was_set(void)
      98             : {
      99           0 :         ktime_t moffs = ktime_mono_to_real(0);
     100             :         struct timerfd_ctx *ctx;
     101             :         unsigned long flags;
     102             : 
     103             :         rcu_read_lock();
     104           0 :         list_for_each_entry_rcu(ctx, &cancel_list, clist) {
     105           0 :                 if (!ctx->might_cancel)
     106           0 :                         continue;
     107           0 :                 spin_lock_irqsave(&ctx->wqh.lock, flags);
     108           0 :                 if (ctx->moffs != moffs) {
     109           0 :                         ctx->moffs = KTIME_MAX;
     110           0 :                         ctx->ticks++;
     111           0 :                         wake_up_locked_poll(&ctx->wqh, EPOLLIN);
     112             :                 }
     113           0 :                 spin_unlock_irqrestore(&ctx->wqh.lock, flags);
     114             :         }
     115             :         rcu_read_unlock();
     116           0 : }
     117             : 
     118           0 : static void timerfd_resume_work(struct work_struct *work)
     119             : {
     120           0 :         timerfd_clock_was_set();
     121           0 : }
     122             : 
     123             : static DECLARE_WORK(timerfd_work, timerfd_resume_work);
     124             : 
     125             : /*
     126             :  * Invoked from timekeeping_resume(). Defer the actual update to work so
     127             :  * timerfd_clock_was_set() runs in task context.
     128             :  */
     129           0 : void timerfd_resume(void)
     130             : {
     131           0 :         schedule_work(&timerfd_work);
     132           0 : }
     133             : 
     134             : static void __timerfd_remove_cancel(struct timerfd_ctx *ctx)
     135             : {
     136           0 :         if (ctx->might_cancel) {
     137           0 :                 ctx->might_cancel = false;
     138           0 :                 spin_lock(&cancel_lock);
     139           0 :                 list_del_rcu(&ctx->clist);
     140             :                 spin_unlock(&cancel_lock);
     141             :         }
     142             : }
     143             : 
     144             : static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
     145             : {
     146           0 :         spin_lock(&ctx->cancel_lock);
     147           0 :         __timerfd_remove_cancel(ctx);
     148           0 :         spin_unlock(&ctx->cancel_lock);
     149             : }
     150             : 
     151             : static bool timerfd_canceled(struct timerfd_ctx *ctx)
     152             : {
     153           0 :         if (!ctx->might_cancel || ctx->moffs != KTIME_MAX)
     154             :                 return false;
     155           0 :         ctx->moffs = ktime_mono_to_real(0);
     156             :         return true;
     157             : }
     158             : 
     159           0 : static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
     160             : {
     161           0 :         spin_lock(&ctx->cancel_lock);
     162           0 :         if ((ctx->clockid == CLOCK_REALTIME ||
     163             :              ctx->clockid == CLOCK_REALTIME_ALARM) &&
     164           0 :             (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
     165           0 :                 if (!ctx->might_cancel) {
     166           0 :                         ctx->might_cancel = true;
     167           0 :                         spin_lock(&cancel_lock);
     168           0 :                         list_add_rcu(&ctx->clist, &cancel_list);
     169             :                         spin_unlock(&cancel_lock);
     170             :                 }
     171             :         } else {
     172             :                 __timerfd_remove_cancel(ctx);
     173             :         }
     174           0 :         spin_unlock(&ctx->cancel_lock);
     175           0 : }
     176             : 
     177           0 : static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
     178             : {
     179             :         ktime_t remaining;
     180             : 
     181           0 :         if (isalarm(ctx))
     182           0 :                 remaining = alarm_expires_remaining(&ctx->t.alarm);
     183             :         else
     184           0 :                 remaining = hrtimer_expires_remaining_adjusted(&ctx->t.tmr);
     185             : 
     186           0 :         return remaining < 0 ? 0: remaining;
     187             : }
     188             : 
     189           0 : static int timerfd_setup(struct timerfd_ctx *ctx, int flags,
     190             :                          const struct itimerspec64 *ktmr)
     191             : {
     192             :         enum hrtimer_mode htmode;
     193             :         ktime_t texp;
     194           0 :         int clockid = ctx->clockid;
     195             : 
     196           0 :         htmode = (flags & TFD_TIMER_ABSTIME) ?
     197           0 :                 HRTIMER_MODE_ABS: HRTIMER_MODE_REL;
     198             : 
     199           0 :         texp = timespec64_to_ktime(ktmr->it_value);
     200           0 :         ctx->expired = 0;
     201           0 :         ctx->ticks = 0;
     202           0 :         ctx->tintv = timespec64_to_ktime(ktmr->it_interval);
     203             : 
     204           0 :         if (isalarm(ctx)) {
     205           0 :                 alarm_init(&ctx->t.alarm,
     206             :                            ctx->clockid == CLOCK_REALTIME_ALARM ?
     207             :                            ALARM_REALTIME : ALARM_BOOTTIME,
     208             :                            timerfd_alarmproc);
     209             :         } else {
     210           0 :                 hrtimer_init(&ctx->t.tmr, clockid, htmode);
     211           0 :                 hrtimer_set_expires(&ctx->t.tmr, texp);
     212           0 :                 ctx->t.tmr.function = timerfd_tmrproc;
     213             :         }
     214             : 
     215           0 :         if (texp != 0) {
     216             :                 if (flags & TFD_TIMER_ABSTIME)
     217             :                         texp = timens_ktime_to_host(clockid, texp);
     218           0 :                 if (isalarm(ctx)) {
     219           0 :                         if (flags & TFD_TIMER_ABSTIME)
     220           0 :                                 alarm_start(&ctx->t.alarm, texp);
     221             :                         else
     222           0 :                                 alarm_start_relative(&ctx->t.alarm, texp);
     223             :                 } else {
     224           0 :                         hrtimer_start(&ctx->t.tmr, texp, htmode);
     225             :                 }
     226             : 
     227           0 :                 if (timerfd_canceled(ctx))
     228             :                         return -ECANCELED;
     229             :         }
     230             : 
     231           0 :         ctx->settime_flags = flags & TFD_SETTIME_FLAGS;
     232           0 :         return 0;
     233             : }
     234             : 
     235           0 : static int timerfd_release(struct inode *inode, struct file *file)
     236             : {
     237           0 :         struct timerfd_ctx *ctx = file->private_data;
     238             : 
     239           0 :         timerfd_remove_cancel(ctx);
     240             : 
     241           0 :         if (isalarm(ctx))
     242           0 :                 alarm_cancel(&ctx->t.alarm);
     243             :         else
     244           0 :                 hrtimer_cancel(&ctx->t.tmr);
     245           0 :         kfree_rcu(ctx, rcu);
     246           0 :         return 0;
     247             : }
     248             : 
     249           0 : static __poll_t timerfd_poll(struct file *file, poll_table *wait)
     250             : {
     251           0 :         struct timerfd_ctx *ctx = file->private_data;
     252           0 :         __poll_t events = 0;
     253             :         unsigned long flags;
     254             : 
     255           0 :         poll_wait(file, &ctx->wqh, wait);
     256             : 
     257           0 :         spin_lock_irqsave(&ctx->wqh.lock, flags);
     258           0 :         if (ctx->ticks)
     259           0 :                 events |= EPOLLIN;
     260           0 :         spin_unlock_irqrestore(&ctx->wqh.lock, flags);
     261             : 
     262           0 :         return events;
     263             : }
     264             : 
     265           0 : static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
     266             :                             loff_t *ppos)
     267             : {
     268           0 :         struct timerfd_ctx *ctx = file->private_data;
     269             :         ssize_t res;
     270           0 :         u64 ticks = 0;
     271             : 
     272           0 :         if (count < sizeof(ticks))
     273             :                 return -EINVAL;
     274           0 :         spin_lock_irq(&ctx->wqh.lock);
     275           0 :         if (file->f_flags & O_NONBLOCK)
     276             :                 res = -EAGAIN;
     277             :         else
     278           0 :                 res = wait_event_interruptible_locked_irq(ctx->wqh, ctx->ticks);
     279             : 
     280             :         /*
     281             :          * If clock has changed, we do not care about the
     282             :          * ticks and we do not rearm the timer. Userspace must
     283             :          * reevaluate anyway.
     284             :          */
     285           0 :         if (timerfd_canceled(ctx)) {
     286           0 :                 ctx->ticks = 0;
     287           0 :                 ctx->expired = 0;
     288           0 :                 res = -ECANCELED;
     289             :         }
     290             : 
     291           0 :         if (ctx->ticks) {
     292           0 :                 ticks = ctx->ticks;
     293             : 
     294           0 :                 if (ctx->expired && ctx->tintv) {
     295             :                         /*
     296             :                          * If tintv != 0, this is a periodic timer that
     297             :                          * needs to be re-armed. We avoid doing it in the timer
     298             :                          * callback to avoid DoS attacks specifying a very
     299             :                          * short timer period.
     300             :                          */
     301           0 :                         if (isalarm(ctx)) {
     302           0 :                                 ticks += alarm_forward_now(
     303           0 :                                         &ctx->t.alarm, ctx->tintv) - 1;
     304           0 :                                 alarm_restart(&ctx->t.alarm);
     305             :                         } else {
     306           0 :                                 ticks += hrtimer_forward_now(&ctx->t.tmr,
     307           0 :                                                              ctx->tintv) - 1;
     308           0 :                                 hrtimer_restart(&ctx->t.tmr);
     309             :                         }
     310             :                 }
     311           0 :                 ctx->expired = 0;
     312           0 :                 ctx->ticks = 0;
     313             :         }
     314           0 :         spin_unlock_irq(&ctx->wqh.lock);
     315           0 :         if (ticks)
     316           0 :                 res = put_user(ticks, (u64 __user *) buf) ? -EFAULT: sizeof(ticks);
     317             :         return res;
     318             : }
     319             : 
     320             : #ifdef CONFIG_PROC_FS
     321           0 : static void timerfd_show(struct seq_file *m, struct file *file)
     322             : {
     323           0 :         struct timerfd_ctx *ctx = file->private_data;
     324             :         struct timespec64 value, interval;
     325             : 
     326           0 :         spin_lock_irq(&ctx->wqh.lock);
     327           0 :         value = ktime_to_timespec64(timerfd_get_remaining(ctx));
     328           0 :         interval = ktime_to_timespec64(ctx->tintv);
     329           0 :         spin_unlock_irq(&ctx->wqh.lock);
     330             : 
     331           0 :         seq_printf(m,
     332             :                    "clockid: %d\n"
     333             :                    "ticks: %llu\n"
     334             :                    "settime flags: 0%o\n"
     335             :                    "it_value: (%llu, %llu)\n"
     336             :                    "it_interval: (%llu, %llu)\n",
     337             :                    ctx->clockid,
     338           0 :                    (unsigned long long)ctx->ticks,
     339           0 :                    ctx->settime_flags,
     340           0 :                    (unsigned long long)value.tv_sec,
     341           0 :                    (unsigned long long)value.tv_nsec,
     342           0 :                    (unsigned long long)interval.tv_sec,
     343           0 :                    (unsigned long long)interval.tv_nsec);
     344           0 : }
     345             : #else
     346             : #define timerfd_show NULL
     347             : #endif
     348             : 
     349             : #ifdef CONFIG_CHECKPOINT_RESTORE
     350             : static long timerfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
     351             : {
     352             :         struct timerfd_ctx *ctx = file->private_data;
     353             :         int ret = 0;
     354             : 
     355             :         switch (cmd) {
     356             :         case TFD_IOC_SET_TICKS: {
     357             :                 u64 ticks;
     358             : 
     359             :                 if (copy_from_user(&ticks, (u64 __user *)arg, sizeof(ticks)))
     360             :                         return -EFAULT;
     361             :                 if (!ticks)
     362             :                         return -EINVAL;
     363             : 
     364             :                 spin_lock_irq(&ctx->wqh.lock);
     365             :                 if (!timerfd_canceled(ctx)) {
     366             :                         ctx->ticks = ticks;
     367             :                         wake_up_locked_poll(&ctx->wqh, EPOLLIN);
     368             :                 } else
     369             :                         ret = -ECANCELED;
     370             :                 spin_unlock_irq(&ctx->wqh.lock);
     371             :                 break;
     372             :         }
     373             :         default:
     374             :                 ret = -ENOTTY;
     375             :                 break;
     376             :         }
     377             : 
     378             :         return ret;
     379             : }
     380             : #else
     381             : #define timerfd_ioctl NULL
     382             : #endif
     383             : 
     384             : static const struct file_operations timerfd_fops = {
     385             :         .release        = timerfd_release,
     386             :         .poll           = timerfd_poll,
     387             :         .read           = timerfd_read,
     388             :         .llseek         = noop_llseek,
     389             :         .show_fdinfo    = timerfd_show,
     390             :         .unlocked_ioctl = timerfd_ioctl,
     391             : };
     392             : 
     393           0 : static int timerfd_fget(int fd, struct fd *p)
     394             : {
     395           0 :         struct fd f = fdget(fd);
     396           0 :         if (!f.file)
     397             :                 return -EBADF;
     398           0 :         if (f.file->f_op != &timerfd_fops) {
     399           0 :                 fdput(f);
     400             :                 return -EINVAL;
     401             :         }
     402           0 :         *p = f;
     403           0 :         return 0;
     404             : }
     405             : 
     406           0 : SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
     407             : {
     408             :         int ufd;
     409             :         struct timerfd_ctx *ctx;
     410             : 
     411             :         /* Check the TFD_* constants for consistency.  */
     412             :         BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC);
     413             :         BUILD_BUG_ON(TFD_NONBLOCK != O_NONBLOCK);
     414             : 
     415           0 :         if ((flags & ~TFD_CREATE_FLAGS) ||
     416           0 :             (clockid != CLOCK_MONOTONIC &&
     417           0 :              clockid != CLOCK_REALTIME &&
     418           0 :              clockid != CLOCK_REALTIME_ALARM &&
     419           0 :              clockid != CLOCK_BOOTTIME &&
     420           0 :              clockid != CLOCK_BOOTTIME_ALARM))
     421             :                 return -EINVAL;
     422             : 
     423           0 :         if ((clockid == CLOCK_REALTIME_ALARM ||
     424           0 :              clockid == CLOCK_BOOTTIME_ALARM) &&
     425           0 :             !capable(CAP_WAKE_ALARM))
     426             :                 return -EPERM;
     427             : 
     428           0 :         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
     429           0 :         if (!ctx)
     430             :                 return -ENOMEM;
     431             : 
     432           0 :         init_waitqueue_head(&ctx->wqh);
     433           0 :         spin_lock_init(&ctx->cancel_lock);
     434           0 :         ctx->clockid = clockid;
     435             : 
     436           0 :         if (isalarm(ctx))
     437           0 :                 alarm_init(&ctx->t.alarm,
     438             :                            ctx->clockid == CLOCK_REALTIME_ALARM ?
     439             :                            ALARM_REALTIME : ALARM_BOOTTIME,
     440             :                            timerfd_alarmproc);
     441             :         else
     442           0 :                 hrtimer_init(&ctx->t.tmr, clockid, HRTIMER_MODE_ABS);
     443             : 
     444           0 :         ctx->moffs = ktime_mono_to_real(0);
     445             : 
     446           0 :         ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx,
     447           0 :                                O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS));
     448           0 :         if (ufd < 0)
     449           0 :                 kfree(ctx);
     450             : 
     451           0 :         return ufd;
     452             : }
     453             : 
     454           0 : static int do_timerfd_settime(int ufd, int flags, 
     455             :                 const struct itimerspec64 *new,
     456             :                 struct itimerspec64 *old)
     457             : {
     458             :         struct fd f;
     459             :         struct timerfd_ctx *ctx;
     460             :         int ret;
     461             : 
     462           0 :         if ((flags & ~TFD_SETTIME_FLAGS) ||
     463           0 :                  !itimerspec64_valid(new))
     464             :                 return -EINVAL;
     465             : 
     466           0 :         ret = timerfd_fget(ufd, &f);
     467           0 :         if (ret)
     468             :                 return ret;
     469           0 :         ctx = f.file->private_data;
     470             : 
     471           0 :         if (isalarm(ctx) && !capable(CAP_WAKE_ALARM)) {
     472           0 :                 fdput(f);
     473             :                 return -EPERM;
     474             :         }
     475             : 
     476           0 :         timerfd_setup_cancel(ctx, flags);
     477             : 
     478             :         /*
     479             :          * We need to stop the existing timer before reprogramming
     480             :          * it to the new values.
     481             :          */
     482             :         for (;;) {
     483           0 :                 spin_lock_irq(&ctx->wqh.lock);
     484             : 
     485           0 :                 if (isalarm(ctx)) {
     486           0 :                         if (alarm_try_to_cancel(&ctx->t.alarm) >= 0)
     487             :                                 break;
     488             :                 } else {
     489           0 :                         if (hrtimer_try_to_cancel(&ctx->t.tmr) >= 0)
     490             :                                 break;
     491             :                 }
     492           0 :                 spin_unlock_irq(&ctx->wqh.lock);
     493             : 
     494           0 :                 if (isalarm(ctx))
     495           0 :                         hrtimer_cancel_wait_running(&ctx->t.alarm.timer);
     496             :                 else
     497           0 :                         hrtimer_cancel_wait_running(&ctx->t.tmr);
     498             :         }
     499             : 
     500             :         /*
     501             :          * If the timer is expired and it's periodic, we need to advance it
     502             :          * because the caller may want to know the previous expiration time.
     503             :          * We do not update "ticks" and "expired" since the timer will be
     504             :          * re-programmed again in the following timerfd_setup() call.
     505             :          */
     506           0 :         if (ctx->expired && ctx->tintv) {
     507           0 :                 if (isalarm(ctx))
     508           0 :                         alarm_forward_now(&ctx->t.alarm, ctx->tintv);
     509             :                 else
     510           0 :                         hrtimer_forward_now(&ctx->t.tmr, ctx->tintv);
     511             :         }
     512             : 
     513           0 :         old->it_value = ktime_to_timespec64(timerfd_get_remaining(ctx));
     514           0 :         old->it_interval = ktime_to_timespec64(ctx->tintv);
     515             : 
     516             :         /*
     517             :          * Re-program the timer to the new value ...
     518             :          */
     519           0 :         ret = timerfd_setup(ctx, flags, new);
     520             : 
     521           0 :         spin_unlock_irq(&ctx->wqh.lock);
     522           0 :         fdput(f);
     523             :         return ret;
     524             : }
     525             : 
     526           0 : static int do_timerfd_gettime(int ufd, struct itimerspec64 *t)
     527             : {
     528             :         struct fd f;
     529             :         struct timerfd_ctx *ctx;
     530           0 :         int ret = timerfd_fget(ufd, &f);
     531           0 :         if (ret)
     532             :                 return ret;
     533           0 :         ctx = f.file->private_data;
     534             : 
     535           0 :         spin_lock_irq(&ctx->wqh.lock);
     536           0 :         if (ctx->expired && ctx->tintv) {
     537           0 :                 ctx->expired = 0;
     538             : 
     539           0 :                 if (isalarm(ctx)) {
     540           0 :                         ctx->ticks +=
     541           0 :                                 alarm_forward_now(
     542           0 :                                         &ctx->t.alarm, ctx->tintv) - 1;
     543           0 :                         alarm_restart(&ctx->t.alarm);
     544             :                 } else {
     545           0 :                         ctx->ticks +=
     546           0 :                                 hrtimer_forward_now(&ctx->t.tmr, ctx->tintv)
     547           0 :                                 - 1;
     548           0 :                         hrtimer_restart(&ctx->t.tmr);
     549             :                 }
     550             :         }
     551           0 :         t->it_value = ktime_to_timespec64(timerfd_get_remaining(ctx));
     552           0 :         t->it_interval = ktime_to_timespec64(ctx->tintv);
     553           0 :         spin_unlock_irq(&ctx->wqh.lock);
     554           0 :         fdput(f);
     555             :         return 0;
     556             : }
     557             : 
     558           0 : SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
     559             :                 const struct __kernel_itimerspec __user *, utmr,
     560             :                 struct __kernel_itimerspec __user *, otmr)
     561             : {
     562             :         struct itimerspec64 new, old;
     563             :         int ret;
     564             : 
     565           0 :         if (get_itimerspec64(&new, utmr))
     566             :                 return -EFAULT;
     567           0 :         ret = do_timerfd_settime(ufd, flags, &new, &old);
     568           0 :         if (ret)
     569           0 :                 return ret;
     570           0 :         if (otmr && put_itimerspec64(&old, otmr))
     571             :                 return -EFAULT;
     572             : 
     573           0 :         return ret;
     574             : }
     575             : 
     576           0 : SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct __kernel_itimerspec __user *, otmr)
     577             : {
     578             :         struct itimerspec64 kotmr;
     579           0 :         int ret = do_timerfd_gettime(ufd, &kotmr);
     580           0 :         if (ret)
     581           0 :                 return ret;
     582           0 :         return put_itimerspec64(&kotmr, otmr) ? -EFAULT : 0;
     583             : }
     584             : 
     585             : #ifdef CONFIG_COMPAT_32BIT_TIME
     586             : SYSCALL_DEFINE4(timerfd_settime32, int, ufd, int, flags,
     587             :                 const struct old_itimerspec32 __user *, utmr,
     588             :                 struct old_itimerspec32 __user *, otmr)
     589             : {
     590             :         struct itimerspec64 new, old;
     591             :         int ret;
     592             : 
     593             :         if (get_old_itimerspec32(&new, utmr))
     594             :                 return -EFAULT;
     595             :         ret = do_timerfd_settime(ufd, flags, &new, &old);
     596             :         if (ret)
     597             :                 return ret;
     598             :         if (otmr && put_old_itimerspec32(&old, otmr))
     599             :                 return -EFAULT;
     600             :         return ret;
     601             : }
     602             : 
     603             : SYSCALL_DEFINE2(timerfd_gettime32, int, ufd,
     604             :                 struct old_itimerspec32 __user *, otmr)
     605             : {
     606             :         struct itimerspec64 kotmr;
     607             :         int ret = do_timerfd_gettime(ufd, &kotmr);
     608             :         if (ret)
     609             :                 return ret;
     610             :         return put_old_itimerspec32(&kotmr, otmr) ? -EFAULT : 0;
     611             : }
     612             : #endif

Generated by: LCOV version 1.14