LCOV - code coverage report
Current view: top level - fs - timerfd.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 128 198 64.6 %
Date: 2020-09-30 20:25:40 Functions: 18 27 66.7 %
Branches: 69 136 50.7 %

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

Generated by: LCOV version 1.14