LCOV - code coverage report
Current view: top level - fs - timerfd.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 155 259 59.8 %
Date: 2021-04-22 12:43:58 Functions: 17 26 65.4 %

          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        1438 : static inline bool isalarm(struct timerfd_ctx *ctx)
      53             : {
      54        1438 :         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         104 : static void timerfd_triggered(struct timerfd_ctx *ctx)
      64             : {
      65         104 :         unsigned long flags;
      66             : 
      67         104 :         spin_lock_irqsave(&ctx->wqh.lock, flags);
      68         104 :         ctx->expired = 1;
      69         104 :         ctx->ticks++;
      70         104 :         wake_up_locked_poll(&ctx->wqh, EPOLLIN);
      71         104 :         spin_unlock_irqrestore(&ctx->wqh.lock, flags);
      72         104 : }
      73             : 
      74         104 : static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
      75             : {
      76         104 :         struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx,
      77             :                                                t.tmr);
      78         104 :         timerfd_triggered(ctx);
      79         104 :         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           0 :         struct timerfd_ctx *ctx;
     101           0 :         unsigned long flags;
     102             : 
     103           0 :         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           0 :         rcu_read_unlock();
     116           0 : }
     117             : 
     118         291 : static void __timerfd_remove_cancel(struct timerfd_ctx *ctx)
     119             : {
     120         291 :         if (ctx->might_cancel) {
     121           0 :                 ctx->might_cancel = false;
     122           0 :                 spin_lock(&cancel_lock);
     123           0 :                 list_del_rcu(&ctx->clist);
     124           0 :                 spin_unlock(&cancel_lock);
     125             :         }
     126         291 : }
     127             : 
     128          11 : static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
     129             : {
     130          11 :         spin_lock(&ctx->cancel_lock);
     131          11 :         __timerfd_remove_cancel(ctx);
     132          11 :         spin_unlock(&ctx->cancel_lock);
     133          11 : }
     134             : 
     135         371 : static bool timerfd_canceled(struct timerfd_ctx *ctx)
     136             : {
     137         371 :         if (!ctx->might_cancel || ctx->moffs != KTIME_MAX)
     138             :                 return false;
     139           0 :         ctx->moffs = ktime_mono_to_real(0);
     140           0 :         return true;
     141             : }
     142             : 
     143         282 : static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
     144             : {
     145         282 :         spin_lock(&ctx->cancel_lock);
     146         282 :         if ((ctx->clockid == CLOCK_REALTIME ||
     147             :              ctx->clockid == CLOCK_REALTIME_ALARM) &&
     148           9 :             (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
     149           2 :                 if (!ctx->might_cancel) {
     150           2 :                         ctx->might_cancel = true;
     151           2 :                         spin_lock(&cancel_lock);
     152           2 :                         list_add_rcu(&ctx->clist, &cancel_list);
     153           2 :                         spin_unlock(&cancel_lock);
     154             :                 }
     155             :         } else {
     156         280 :                 __timerfd_remove_cancel(ctx);
     157             :         }
     158         282 :         spin_unlock(&ctx->cancel_lock);
     159         282 : }
     160             : 
     161         282 : static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
     162             : {
     163         282 :         ktime_t remaining;
     164             : 
     165         282 :         if (isalarm(ctx))
     166           0 :                 remaining = alarm_expires_remaining(&ctx->t.alarm);
     167             :         else
     168         282 :                 remaining = hrtimer_expires_remaining_adjusted(&ctx->t.tmr);
     169             : 
     170         282 :         return remaining < 0 ? 0: remaining;
     171             : }
     172             : 
     173         282 : static int timerfd_setup(struct timerfd_ctx *ctx, int flags,
     174             :                          const struct itimerspec64 *ktmr)
     175             : {
     176         282 :         enum hrtimer_mode htmode;
     177         282 :         ktime_t texp;
     178         282 :         int clockid = ctx->clockid;
     179             : 
     180         282 :         htmode = (flags & TFD_TIMER_ABSTIME) ?
     181             :                 HRTIMER_MODE_ABS: HRTIMER_MODE_REL;
     182             : 
     183         282 :         texp = timespec64_to_ktime(ktmr->it_value);
     184         282 :         ctx->expired = 0;
     185         282 :         ctx->ticks = 0;
     186         282 :         ctx->tintv = timespec64_to_ktime(ktmr->it_interval);
     187             : 
     188         282 :         if (isalarm(ctx)) {
     189           0 :                 alarm_init(&ctx->t.alarm,
     190             :                            ctx->clockid == CLOCK_REALTIME_ALARM ?
     191             :                            ALARM_REALTIME : ALARM_BOOTTIME,
     192             :                            timerfd_alarmproc);
     193             :         } else {
     194         282 :                 hrtimer_init(&ctx->t.tmr, clockid, htmode);
     195         282 :                 hrtimer_set_expires(&ctx->t.tmr, texp);
     196         282 :                 ctx->t.tmr.function = timerfd_tmrproc;
     197             :         }
     198             : 
     199         282 :         if (texp != 0) {
     200         275 :                 if (flags & TFD_TIMER_ABSTIME)
     201         275 :                         texp = timens_ktime_to_host(clockid, texp);
     202         275 :                 if (isalarm(ctx)) {
     203           0 :                         if (flags & TFD_TIMER_ABSTIME)
     204           0 :                                 alarm_start(&ctx->t.alarm, texp);
     205             :                         else
     206           0 :                                 alarm_start_relative(&ctx->t.alarm, texp);
     207             :                 } else {
     208         275 :                         hrtimer_start(&ctx->t.tmr, texp, htmode);
     209             :                 }
     210             : 
     211         275 :                 if (timerfd_canceled(ctx))
     212             :                         return -ECANCELED;
     213             :         }
     214             : 
     215         282 :         ctx->settime_flags = flags & TFD_SETTIME_FLAGS;
     216         282 :         return 0;
     217             : }
     218             : 
     219          11 : static int timerfd_release(struct inode *inode, struct file *file)
     220             : {
     221          11 :         struct timerfd_ctx *ctx = file->private_data;
     222             : 
     223          11 :         timerfd_remove_cancel(ctx);
     224             : 
     225          11 :         if (isalarm(ctx))
     226           0 :                 alarm_cancel(&ctx->t.alarm);
     227             :         else
     228          11 :                 hrtimer_cancel(&ctx->t.tmr);
     229          11 :         kfree_rcu(ctx, rcu);
     230          11 :         return 0;
     231             : }
     232             : 
     233         216 : static __poll_t timerfd_poll(struct file *file, poll_table *wait)
     234             : {
     235         216 :         struct timerfd_ctx *ctx = file->private_data;
     236         216 :         __poll_t events = 0;
     237         216 :         unsigned long flags;
     238             : 
     239         216 :         poll_wait(file, &ctx->wqh, wait);
     240             : 
     241         216 :         spin_lock_irqsave(&ctx->wqh.lock, flags);
     242         216 :         if (ctx->ticks)
     243          96 :                 events |= EPOLLIN;
     244         216 :         spin_unlock_irqrestore(&ctx->wqh.lock, flags);
     245             : 
     246         216 :         return events;
     247             : }
     248             : 
     249          96 : static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
     250             :                             loff_t *ppos)
     251             : {
     252          96 :         struct timerfd_ctx *ctx = file->private_data;
     253          96 :         ssize_t res;
     254          96 :         u64 ticks = 0;
     255             : 
     256          96 :         if (count < sizeof(ticks))
     257             :                 return -EINVAL;
     258          96 :         spin_lock_irq(&ctx->wqh.lock);
     259          96 :         if (file->f_flags & O_NONBLOCK)
     260             :                 res = -EAGAIN;
     261             :         else
     262           0 :                 res = wait_event_interruptible_locked_irq(ctx->wqh, ctx->ticks);
     263             : 
     264             :         /*
     265             :          * If clock has changed, we do not care about the
     266             :          * ticks and we do not rearm the timer. Userspace must
     267             :          * reevaluate anyway.
     268             :          */
     269          96 :         if (timerfd_canceled(ctx)) {
     270           0 :                 ctx->ticks = 0;
     271           0 :                 ctx->expired = 0;
     272           0 :                 res = -ECANCELED;
     273             :         }
     274             : 
     275          96 :         if (ctx->ticks) {
     276          96 :                 ticks = ctx->ticks;
     277             : 
     278          96 :                 if (ctx->expired && ctx->tintv) {
     279             :                         /*
     280             :                          * If tintv != 0, this is a periodic timer that
     281             :                          * needs to be re-armed. We avoid doing it in the timer
     282             :                          * callback to avoid DoS attacks specifying a very
     283             :                          * short timer period.
     284             :                          */
     285           0 :                         if (isalarm(ctx)) {
     286           0 :                                 ticks += alarm_forward_now(
     287           0 :                                         &ctx->t.alarm, ctx->tintv) - 1;
     288           0 :                                 alarm_restart(&ctx->t.alarm);
     289             :                         } else {
     290           0 :                                 ticks += hrtimer_forward_now(&ctx->t.tmr,
     291           0 :                                                              ctx->tintv) - 1;
     292           0 :                                 hrtimer_restart(&ctx->t.tmr);
     293             :                         }
     294             :                 }
     295          96 :                 ctx->expired = 0;
     296          96 :                 ctx->ticks = 0;
     297             :         }
     298          96 :         spin_unlock_irq(&ctx->wqh.lock);
     299          96 :         if (ticks)
     300          96 :                 res = put_user(ticks, (u64 __user *) buf) ? -EFAULT: sizeof(ticks);
     301             :         return res;
     302             : }
     303             : 
     304             : #ifdef CONFIG_PROC_FS
     305           0 : static void timerfd_show(struct seq_file *m, struct file *file)
     306             : {
     307           0 :         struct timerfd_ctx *ctx = file->private_data;
     308           0 :         struct timespec64 value, interval;
     309             : 
     310           0 :         spin_lock_irq(&ctx->wqh.lock);
     311           0 :         value = ktime_to_timespec64(timerfd_get_remaining(ctx));
     312           0 :         interval = ktime_to_timespec64(ctx->tintv);
     313           0 :         spin_unlock_irq(&ctx->wqh.lock);
     314             : 
     315           0 :         seq_printf(m,
     316             :                    "clockid: %d\n"
     317             :                    "ticks: %llu\n"
     318             :                    "settime flags: 0%o\n"
     319             :                    "it_value: (%llu, %llu)\n"
     320             :                    "it_interval: (%llu, %llu)\n",
     321             :                    ctx->clockid,
     322           0 :                    (unsigned long long)ctx->ticks,
     323           0 :                    ctx->settime_flags,
     324           0 :                    (unsigned long long)value.tv_sec,
     325           0 :                    (unsigned long long)value.tv_nsec,
     326           0 :                    (unsigned long long)interval.tv_sec,
     327           0 :                    (unsigned long long)interval.tv_nsec);
     328           0 : }
     329             : #else
     330             : #define timerfd_show NULL
     331             : #endif
     332             : 
     333             : #ifdef CONFIG_CHECKPOINT_RESTORE
     334             : static long timerfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
     335             : {
     336             :         struct timerfd_ctx *ctx = file->private_data;
     337             :         int ret = 0;
     338             : 
     339             :         switch (cmd) {
     340             :         case TFD_IOC_SET_TICKS: {
     341             :                 u64 ticks;
     342             : 
     343             :                 if (copy_from_user(&ticks, (u64 __user *)arg, sizeof(ticks)))
     344             :                         return -EFAULT;
     345             :                 if (!ticks)
     346             :                         return -EINVAL;
     347             : 
     348             :                 spin_lock_irq(&ctx->wqh.lock);
     349             :                 if (!timerfd_canceled(ctx)) {
     350             :                         ctx->ticks = ticks;
     351             :                         wake_up_locked_poll(&ctx->wqh, EPOLLIN);
     352             :                 } else
     353             :                         ret = -ECANCELED;
     354             :                 spin_unlock_irq(&ctx->wqh.lock);
     355             :                 break;
     356             :         }
     357             :         default:
     358             :                 ret = -ENOTTY;
     359             :                 break;
     360             :         }
     361             : 
     362             :         return ret;
     363             : }
     364             : #else
     365             : #define timerfd_ioctl NULL
     366             : #endif
     367             : 
     368             : static const struct file_operations timerfd_fops = {
     369             :         .release        = timerfd_release,
     370             :         .poll           = timerfd_poll,
     371             :         .read           = timerfd_read,
     372             :         .llseek         = noop_llseek,
     373             :         .show_fdinfo    = timerfd_show,
     374             :         .unlocked_ioctl = timerfd_ioctl,
     375             : };
     376             : 
     377         282 : static int timerfd_fget(int fd, struct fd *p)
     378             : {
     379         282 :         struct fd f = fdget(fd);
     380         282 :         if (!f.file)
     381             :                 return -EBADF;
     382         282 :         if (f.file->f_op != &timerfd_fops) {
     383           0 :                 fdput(f);
     384           0 :                 return -EINVAL;
     385             :         }
     386         282 :         *p = f;
     387         282 :         return 0;
     388             : }
     389             : 
     390          48 : SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
     391             : {
     392          24 :         int ufd;
     393          24 :         struct timerfd_ctx *ctx;
     394             : 
     395             :         /* Check the TFD_* constants for consistency.  */
     396          24 :         BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC);
     397          24 :         BUILD_BUG_ON(TFD_NONBLOCK != O_NONBLOCK);
     398             : 
     399          24 :         if ((flags & ~TFD_CREATE_FLAGS) ||
     400          24 :             (clockid != CLOCK_MONOTONIC &&
     401          24 :              clockid != CLOCK_REALTIME &&
     402          24 :              clockid != CLOCK_REALTIME_ALARM &&
     403           8 :              clockid != CLOCK_BOOTTIME &&
     404           8 :              clockid != CLOCK_BOOTTIME_ALARM))
     405             :                 return -EINVAL;
     406             : 
     407          24 :         if ((clockid == CLOCK_REALTIME_ALARM ||
     408           0 :              clockid == CLOCK_BOOTTIME_ALARM) &&
     409           0 :             !capable(CAP_WAKE_ALARM))
     410             :                 return -EPERM;
     411             : 
     412          24 :         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
     413          24 :         if (!ctx)
     414             :                 return -ENOMEM;
     415             : 
     416          24 :         init_waitqueue_head(&ctx->wqh);
     417          24 :         spin_lock_init(&ctx->cancel_lock);
     418          24 :         ctx->clockid = clockid;
     419             : 
     420          24 :         if (isalarm(ctx))
     421           0 :                 alarm_init(&ctx->t.alarm,
     422             :                            ctx->clockid == CLOCK_REALTIME_ALARM ?
     423             :                            ALARM_REALTIME : ALARM_BOOTTIME,
     424             :                            timerfd_alarmproc);
     425             :         else
     426          24 :                 hrtimer_init(&ctx->t.tmr, clockid, HRTIMER_MODE_ABS);
     427             : 
     428          24 :         ctx->moffs = ktime_mono_to_real(0);
     429             : 
     430          48 :         ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx,
     431          24 :                                O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS));
     432          24 :         if (ufd < 0)
     433           0 :                 kfree(ctx);
     434             : 
     435          24 :         return ufd;
     436             : }
     437             : 
     438         282 : static int do_timerfd_settime(int ufd, int flags, 
     439             :                 const struct itimerspec64 *new,
     440             :                 struct itimerspec64 *old)
     441             : {
     442         282 :         struct fd f;
     443         282 :         struct timerfd_ctx *ctx;
     444         282 :         int ret;
     445             : 
     446         282 :         if ((flags & ~TFD_SETTIME_FLAGS) ||
     447         282 :                  !itimerspec64_valid(new))
     448             :                 return -EINVAL;
     449             : 
     450         282 :         ret = timerfd_fget(ufd, &f);
     451         282 :         if (ret)
     452             :                 return ret;
     453         282 :         ctx = f.file->private_data;
     454             : 
     455         282 :         if (isalarm(ctx) && !capable(CAP_WAKE_ALARM)) {
     456           0 :                 fdput(f);
     457           0 :                 return -EPERM;
     458             :         }
     459             : 
     460         282 :         timerfd_setup_cancel(ctx, flags);
     461             : 
     462             :         /*
     463             :          * We need to stop the existing timer before reprogramming
     464             :          * it to the new values.
     465             :          */
     466         282 :         for (;;) {
     467         564 :                 spin_lock_irq(&ctx->wqh.lock);
     468             : 
     469         282 :                 if (isalarm(ctx)) {
     470           0 :                         if (alarm_try_to_cancel(&ctx->t.alarm) >= 0)
     471             :                                 break;
     472             :                 } else {
     473         282 :                         if (hrtimer_try_to_cancel(&ctx->t.tmr) >= 0)
     474             :                                 break;
     475             :                 }
     476           0 :                 spin_unlock_irq(&ctx->wqh.lock);
     477             : 
     478           0 :                 if (isalarm(ctx))
     479           0 :                         hrtimer_cancel_wait_running(&ctx->t.alarm.timer);
     480             :                 else
     481         282 :                         hrtimer_cancel_wait_running(&ctx->t.tmr);
     482             :         }
     483             : 
     484             :         /*
     485             :          * If the timer is expired and it's periodic, we need to advance it
     486             :          * because the caller may want to know the previous expiration time.
     487             :          * We do not update "ticks" and "expired" since the timer will be
     488             :          * re-programmed again in the following timerfd_setup() call.
     489             :          */
     490         282 :         if (ctx->expired && ctx->tintv) {
     491           0 :                 if (isalarm(ctx))
     492           0 :                         alarm_forward_now(&ctx->t.alarm, ctx->tintv);
     493             :                 else
     494           0 :                         hrtimer_forward_now(&ctx->t.tmr, ctx->tintv);
     495             :         }
     496             : 
     497         282 :         old->it_value = ktime_to_timespec64(timerfd_get_remaining(ctx));
     498         282 :         old->it_interval = ktime_to_timespec64(ctx->tintv);
     499             : 
     500             :         /*
     501             :          * Re-program the timer to the new value ...
     502             :          */
     503         282 :         ret = timerfd_setup(ctx, flags, new);
     504             : 
     505         282 :         spin_unlock_irq(&ctx->wqh.lock);
     506         282 :         fdput(f);
     507         282 :         return ret;
     508             : }
     509             : 
     510           0 : static int do_timerfd_gettime(int ufd, struct itimerspec64 *t)
     511             : {
     512           0 :         struct fd f;
     513           0 :         struct timerfd_ctx *ctx;
     514           0 :         int ret = timerfd_fget(ufd, &f);
     515           0 :         if (ret)
     516             :                 return ret;
     517           0 :         ctx = f.file->private_data;
     518             : 
     519           0 :         spin_lock_irq(&ctx->wqh.lock);
     520           0 :         if (ctx->expired && ctx->tintv) {
     521           0 :                 ctx->expired = 0;
     522             : 
     523           0 :                 if (isalarm(ctx)) {
     524           0 :                         ctx->ticks +=
     525           0 :                                 alarm_forward_now(
     526           0 :                                         &ctx->t.alarm, ctx->tintv) - 1;
     527           0 :                         alarm_restart(&ctx->t.alarm);
     528             :                 } else {
     529           0 :                         ctx->ticks +=
     530           0 :                                 hrtimer_forward_now(&ctx->t.tmr, ctx->tintv)
     531           0 :                                 - 1;
     532           0 :                         hrtimer_restart(&ctx->t.tmr);
     533             :                 }
     534             :         }
     535           0 :         t->it_value = ktime_to_timespec64(timerfd_get_remaining(ctx));
     536           0 :         t->it_interval = ktime_to_timespec64(ctx->tintv);
     537           0 :         spin_unlock_irq(&ctx->wqh.lock);
     538           0 :         fdput(f);
     539           0 :         return 0;
     540             : }
     541             : 
     542         564 : SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
     543             :                 const struct __kernel_itimerspec __user *, utmr,
     544             :                 struct __kernel_itimerspec __user *, otmr)
     545             : {
     546         282 :         struct itimerspec64 new, old;
     547         282 :         int ret;
     548             : 
     549         282 :         if (get_itimerspec64(&new, utmr))
     550             :                 return -EFAULT;
     551         282 :         ret = do_timerfd_settime(ufd, flags, &new, &old);
     552         282 :         if (ret)
     553           0 :                 return ret;
     554         282 :         if (otmr && put_itimerspec64(&old, otmr))
     555           0 :                 return -EFAULT;
     556             : 
     557             :         return ret;
     558             : }
     559             : 
     560           0 : SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct __kernel_itimerspec __user *, otmr)
     561             : {
     562           0 :         struct itimerspec64 kotmr;
     563           0 :         int ret = do_timerfd_gettime(ufd, &kotmr);
     564           0 :         if (ret)
     565           0 :                 return ret;
     566           0 :         return put_itimerspec64(&kotmr, otmr) ? -EFAULT : 0;
     567             : }
     568             : 
     569             : #ifdef CONFIG_COMPAT_32BIT_TIME
     570             : SYSCALL_DEFINE4(timerfd_settime32, int, ufd, int, flags,
     571             :                 const struct old_itimerspec32 __user *, utmr,
     572             :                 struct old_itimerspec32 __user *, otmr)
     573             : {
     574             :         struct itimerspec64 new, old;
     575             :         int ret;
     576             : 
     577             :         if (get_old_itimerspec32(&new, utmr))
     578             :                 return -EFAULT;
     579             :         ret = do_timerfd_settime(ufd, flags, &new, &old);
     580             :         if (ret)
     581             :                 return ret;
     582             :         if (otmr && put_old_itimerspec32(&old, otmr))
     583             :                 return -EFAULT;
     584             :         return ret;
     585             : }
     586             : 
     587             : SYSCALL_DEFINE2(timerfd_gettime32, int, ufd,
     588             :                 struct old_itimerspec32 __user *, otmr)
     589             : {
     590             :         struct itimerspec64 kotmr;
     591             :         int ret = do_timerfd_gettime(ufd, &kotmr);
     592             :         if (ret)
     593             :                 return ret;
     594             :         return put_old_itimerspec32(&kotmr, otmr) ? -EFAULT : 0;
     595             : }
     596             : #endif

Generated by: LCOV version 1.14