LCOV - code coverage report
Current view: top level - fs - timerfd.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 152 272 55.9 %
Date: 2022-04-01 14:17:54 Functions: 16 31 51.6 %
Branches: 56 154 36.4 %

           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                 :            : #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                 :      11018 : static inline bool isalarm(struct timerfd_ctx *ctx)
      53                 :            : {
      54                 :      11018 :         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                 :         93 : static void timerfd_triggered(struct timerfd_ctx *ctx)
      64                 :            : {
      65                 :         93 :         unsigned long flags;
      66                 :            : 
      67                 :         93 :         spin_lock_irqsave(&ctx->wqh.lock, flags);
      68                 :         93 :         ctx->expired = 1;
      69                 :         93 :         ctx->ticks++;
      70                 :         93 :         wake_up_locked_poll(&ctx->wqh, EPOLLIN);
      71                 :         93 :         spin_unlock_irqrestore(&ctx->wqh.lock, flags);
      72                 :         93 : }
      73                 :            : 
      74                 :         93 : static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
      75                 :            : {
      76                 :         93 :         struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx,
      77                 :            :                                                t.tmr);
      78                 :         93 :         timerfd_triggered(ctx);
      79                 :         93 :         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                 :       2414 : static void __timerfd_remove_cancel(struct timerfd_ctx *ctx)
     119                 :            : {
     120         [ -  + ]:       2414 :         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                 :       2414 : }
     127                 :            : 
     128                 :        143 : static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
     129                 :            : {
     130                 :        143 :         spin_lock(&ctx->cancel_lock);
     131                 :        143 :         __timerfd_remove_cancel(ctx);
     132                 :        143 :         spin_unlock(&ctx->cancel_lock);
     133                 :        143 : }
     134                 :            : 
     135                 :       1576 : static bool timerfd_canceled(struct timerfd_ctx *ctx)
     136                 :            : {
     137   [ -  -  -  + ]:         11 :         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                 :       2282 : static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
     144                 :            : {
     145                 :       2282 :         spin_lock(&ctx->cancel_lock);
     146         [ +  + ]:       2282 :         if ((ctx->clockid == CLOCK_REALTIME ||
     147                 :            :              ctx->clockid == CLOCK_REALTIME_ALARM) &&
     148         [ +  + ]:         22 :             (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
     149         [ +  - ]:         11 :                 if (!ctx->might_cancel) {
     150                 :         11 :                         ctx->might_cancel = true;
     151                 :         11 :                         spin_lock(&cancel_lock);
     152                 :         11 :                         list_add_rcu(&ctx->clist, &cancel_list);
     153                 :         11 :                         spin_unlock(&cancel_lock);
     154                 :            :                 }
     155                 :            :         } else {
     156                 :       2271 :                 __timerfd_remove_cancel(ctx);
     157                 :            :         }
     158                 :       2282 :         spin_unlock(&ctx->cancel_lock);
     159                 :       2282 : }
     160                 :            : 
     161                 :       2282 : static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
     162                 :            : {
     163                 :       2282 :         ktime_t remaining;
     164                 :            : 
     165         [ -  + ]:       2282 :         if (isalarm(ctx))
     166                 :          0 :                 remaining = alarm_expires_remaining(&ctx->t.alarm);
     167                 :            :         else
     168                 :       2282 :                 remaining = hrtimer_expires_remaining_adjusted(&ctx->t.tmr);
     169                 :            : 
     170                 :       2282 :         return remaining < 0 ? 0: remaining;
     171                 :            : }
     172                 :            : 
     173                 :       2282 : static int timerfd_setup(struct timerfd_ctx *ctx, int flags,
     174                 :            :                          const struct itimerspec64 *ktmr)
     175                 :            : {
     176                 :       2282 :         enum hrtimer_mode htmode;
     177                 :       2282 :         ktime_t texp;
     178                 :       2282 :         int clockid = ctx->clockid;
     179                 :            : 
     180                 :       2282 :         htmode = (flags & TFD_TIMER_ABSTIME) ?
     181                 :            :                 HRTIMER_MODE_ABS: HRTIMER_MODE_REL;
     182                 :            : 
     183         [ +  + ]:       2282 :         texp = timespec64_to_ktime(ktmr->it_value);
     184                 :       2282 :         ctx->expired = 0;
     185                 :       2282 :         ctx->ticks = 0;
     186         [ +  - ]:       2282 :         ctx->tintv = timespec64_to_ktime(ktmr->it_interval);
     187                 :            : 
     188         [ -  + ]:       2282 :         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                 :       2282 :                 hrtimer_init(&ctx->t.tmr, clockid, htmode);
     195                 :       2282 :                 hrtimer_set_expires(&ctx->t.tmr, texp);
     196                 :       2282 :                 ctx->t.tmr.function = timerfd_tmrproc;
     197                 :            :         }
     198                 :            : 
     199         [ +  + ]:       2282 :         if (texp != 0) {
     200         [ +  - ]:       1505 :                 if (flags & TFD_TIMER_ABSTIME)
     201         [ -  + ]:       1505 :                         texp = timens_ktime_to_host(clockid, texp);
     202         [ -  + ]:       1505 :                 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                 :       1505 :                         hrtimer_start(&ctx->t.tmr, texp, htmode);
     209                 :            :                 }
     210                 :            : 
     211         [ +  + ]:       1505 :                 if (timerfd_canceled(ctx))
     212                 :          0 :                         return -ECANCELED;
     213                 :            :         }
     214                 :            : 
     215                 :       2282 :         ctx->settime_flags = flags & TFD_SETTIME_FLAGS;
     216                 :       2282 :         return 0;
     217                 :            : }
     218                 :            : 
     219                 :        143 : static int timerfd_release(struct inode *inode, struct file *file)
     220                 :            : {
     221                 :        143 :         struct timerfd_ctx *ctx = file->private_data;
     222                 :            : 
     223                 :        143 :         timerfd_remove_cancel(ctx);
     224                 :            : 
     225         [ -  + ]:        143 :         if (isalarm(ctx))
     226                 :          0 :                 alarm_cancel(&ctx->t.alarm);
     227                 :            :         else
     228                 :        143 :                 hrtimer_cancel(&ctx->t.tmr);
     229         [ +  - ]:        143 :         kfree_rcu(ctx, rcu);
     230                 :        143 :         return 0;
     231                 :            : }
     232                 :            : 
     233                 :        362 : static __poll_t timerfd_poll(struct file *file, poll_table *wait)
     234                 :            : {
     235                 :        362 :         struct timerfd_ctx *ctx = file->private_data;
     236                 :        362 :         __poll_t events = 0;
     237                 :        362 :         unsigned long flags;
     238                 :            : 
     239         [ +  - ]:        362 :         poll_wait(file, &ctx->wqh, wait);
     240                 :            : 
     241                 :        362 :         spin_lock_irqsave(&ctx->wqh.lock, flags);
     242         [ +  + ]:        362 :         if (ctx->ticks)
     243                 :         71 :                 events |= EPOLLIN;
     244                 :        362 :         spin_unlock_irqrestore(&ctx->wqh.lock, flags);
     245                 :            : 
     246                 :        362 :         return events;
     247                 :            : }
     248                 :            : 
     249                 :         71 : static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
     250                 :            :                             loff_t *ppos)
     251                 :            : {
     252                 :         71 :         struct timerfd_ctx *ctx = file->private_data;
     253                 :         71 :         ssize_t res;
     254                 :         71 :         u64 ticks = 0;
     255                 :            : 
     256         [ +  - ]:         71 :         if (count < sizeof(ticks))
     257                 :            :                 return -EINVAL;
     258                 :         71 :         spin_lock_irq(&ctx->wqh.lock);
     259         [ -  + ]:         71 :         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         [ -  + ]:         71 :         if (timerfd_canceled(ctx)) {
     270                 :          0 :                 ctx->ticks = 0;
     271                 :          0 :                 ctx->expired = 0;
     272                 :          0 :                 res = -ECANCELED;
     273                 :            :         }
     274                 :            : 
     275         [ +  - ]:         71 :         if (ctx->ticks) {
     276                 :         71 :                 ticks = ctx->ticks;
     277                 :            : 
     278   [ +  -  -  + ]:         71 :                 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                 :         71 :                 ctx->expired = 0;
     296                 :         71 :                 ctx->ticks = 0;
     297                 :            :         }
     298                 :         71 :         spin_unlock_irq(&ctx->wqh.lock);
     299         [ +  - ]:         71 :         if (ticks)
     300         [ +  - ]:         71 :                 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                 :       2282 : static int timerfd_fget(int fd, struct fd *p)
     378                 :            : {
     379                 :       2282 :         struct fd f = fdget(fd);
     380         [ +  - ]:       2282 :         if (!f.file)
     381                 :            :                 return -EBADF;
     382         [ -  + ]:       2282 :         if (f.file->f_op != &timerfd_fops) {
     383         [ #  # ]:          0 :                 fdput(f);
     384                 :          0 :                 return -EINVAL;
     385                 :            :         }
     386                 :       2282 :         *p = f;
     387                 :       2282 :         return 0;
     388                 :            : }
     389                 :            : 
     390                 :        484 : SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
     391                 :            : {
     392                 :        242 :         int ufd;
     393                 :        242 :         struct timerfd_ctx *ctx;
     394                 :            : 
     395                 :            :         /* Check the TFD_* constants for consistency.  */
     396                 :        242 :         BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC);
     397                 :        242 :         BUILD_BUG_ON(TFD_NONBLOCK != O_NONBLOCK);
     398                 :            : 
     399         [ +  - ]:        242 :         if ((flags & ~TFD_CREATE_FLAGS) ||
     400                 :        242 :             (clockid != CLOCK_MONOTONIC &&
     401                 :        242 :              clockid != CLOCK_REALTIME &&
     402         [ +  + ]:        242 :              clockid != CLOCK_REALTIME_ALARM &&
     403                 :         55 :              clockid != CLOCK_BOOTTIME &&
     404         [ +  - ]:         55 :              clockid != CLOCK_BOOTTIME_ALARM))
     405                 :            :                 return -EINVAL;
     406                 :            : 
     407         [ -  + ]:        242 :         if ((clockid == CLOCK_REALTIME_ALARM ||
     408         [ #  # ]:          0 :              clockid == CLOCK_BOOTTIME_ALARM) &&
     409                 :          0 :             !capable(CAP_WAKE_ALARM))
     410                 :            :                 return -EPERM;
     411                 :            : 
     412                 :        242 :         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
     413         [ +  - ]:        242 :         if (!ctx)
     414                 :            :                 return -ENOMEM;
     415                 :            : 
     416                 :        242 :         init_waitqueue_head(&ctx->wqh);
     417         [ -  + ]:        242 :         spin_lock_init(&ctx->cancel_lock);
     418                 :        242 :         ctx->clockid = clockid;
     419                 :            : 
     420         [ -  + ]:        242 :         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                 :        242 :                 hrtimer_init(&ctx->t.tmr, clockid, HRTIMER_MODE_ABS);
     427                 :            : 
     428                 :        242 :         ctx->moffs = ktime_mono_to_real(0);
     429                 :            : 
     430                 :        242 :         ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx,
     431                 :        242 :                                O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS));
     432         [ -  + ]:        242 :         if (ufd < 0)
     433                 :          0 :                 kfree(ctx);
     434                 :            : 
     435                 :        242 :         return ufd;
     436                 :            : }
     437                 :            : 
     438                 :       2282 : static int do_timerfd_settime(int ufd, int flags, 
     439                 :            :                 const struct itimerspec64 *new,
     440                 :            :                 struct itimerspec64 *old)
     441                 :            : {
     442                 :       2282 :         struct fd f;
     443                 :       2282 :         struct timerfd_ctx *ctx;
     444                 :       2282 :         int ret;
     445                 :            : 
     446         [ +  - ]:       2282 :         if ((flags & ~TFD_SETTIME_FLAGS) ||
     447                 :            :                  !itimerspec64_valid(new))
     448                 :            :                 return -EINVAL;
     449                 :            : 
     450                 :       2282 :         ret = timerfd_fget(ufd, &f);
     451         [ +  - ]:       2282 :         if (ret)
     452                 :            :                 return ret;
     453                 :       2282 :         ctx = f.file->private_data;
     454                 :            : 
     455   [ -  +  -  - ]:       2282 :         if (isalarm(ctx) && !capable(CAP_WAKE_ALARM)) {
     456         [ #  # ]:          0 :                 fdput(f);
     457                 :          0 :                 return -EPERM;
     458                 :            :         }
     459                 :            : 
     460                 :       2282 :         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                 :       2282 :         for (;;) {
     467                 :       2282 :                 spin_lock_irq(&ctx->wqh.lock);
     468                 :            : 
     469         [ -  + ]:       2282 :                 if (isalarm(ctx)) {
     470         [ #  # ]:          0 :                         if (alarm_try_to_cancel(&ctx->t.alarm) >= 0)
     471                 :            :                                 break;
     472                 :            :                 } else {
     473         [ -  + ]:       2282 :                         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                 :          0 :                         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   [ +  +  -  + ]:       2282 :         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                 :       2282 :         old->it_value = ktime_to_timespec64(timerfd_get_remaining(ctx));
     498                 :       2282 :         old->it_interval = ktime_to_timespec64(ctx->tintv);
     499                 :            : 
     500                 :            :         /*
     501                 :            :          * Re-program the timer to the new value ...
     502                 :            :          */
     503                 :       2282 :         ret = timerfd_setup(ctx, flags, new);
     504                 :            : 
     505                 :       2282 :         spin_unlock_irq(&ctx->wqh.lock);
     506         [ +  + ]:       2282 :         fdput(f);
     507                 :            :         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                 :            :         return 0;
     540                 :            : }
     541                 :            : 
     542                 :       4564 : SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
     543                 :            :                 const struct __kernel_itimerspec __user *, utmr,
     544                 :            :                 struct __kernel_itimerspec __user *, otmr)
     545                 :            : {
     546                 :       2282 :         struct itimerspec64 new, old;
     547                 :       2282 :         int ret;
     548                 :            : 
     549         [ +  - ]:       2282 :         if (get_itimerspec64(&new, utmr))
     550                 :            :                 return -EFAULT;
     551                 :       2282 :         ret = do_timerfd_settime(ufd, flags, &new, &old);
     552         [ -  + ]:       2282 :         if (ret)
     553                 :          0 :                 return ret;
     554   [ -  +  -  - ]:       2282 :         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                 :          0 : SYSCALL_DEFINE4(timerfd_settime32, int, ufd, int, flags,
     571                 :            :                 const struct old_itimerspec32 __user *, utmr,
     572                 :            :                 struct old_itimerspec32 __user *, otmr)
     573                 :            : {
     574                 :          0 :         struct itimerspec64 new, old;
     575                 :          0 :         int ret;
     576                 :            : 
     577         [ #  # ]:          0 :         if (get_old_itimerspec32(&new, utmr))
     578                 :            :                 return -EFAULT;
     579                 :          0 :         ret = do_timerfd_settime(ufd, flags, &new, &old);
     580         [ #  # ]:          0 :         if (ret)
     581                 :          0 :                 return ret;
     582   [ #  #  #  # ]:          0 :         if (otmr && put_old_itimerspec32(&old, otmr))
     583                 :          0 :                 return -EFAULT;
     584                 :            :         return ret;
     585                 :            : }
     586                 :            : 
     587                 :          0 : SYSCALL_DEFINE2(timerfd_gettime32, int, ufd,
     588                 :            :                 struct old_itimerspec32 __user *, otmr)
     589                 :            : {
     590                 :          0 :         struct itimerspec64 kotmr;
     591                 :          0 :         int ret = do_timerfd_gettime(ufd, &kotmr);
     592         [ #  # ]:          0 :         if (ret)
     593                 :          0 :                 return ret;
     594         [ #  # ]:          0 :         return put_old_itimerspec32(&kotmr, otmr) ? -EFAULT : 0;
     595                 :            : }
     596                 :            : #endif

Generated by: LCOV version 1.14