LCOV - code coverage report
Current view: top level - fs - timerfd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 106 165 64.2 %
Date: 2014-02-18 Functions: 17 18 94.4 %
Branches: 54 119 45.4 %

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

Generated by: LCOV version 1.9