LCOV - code coverage report
Current view: top level - fs - eventfd.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 157 0.0 %
Date: 2022-04-01 13:59:58 Functions: 0 18 0.0 %
Branches: 0 88 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  *  fs/eventfd.c
       4                 :            :  *
       5                 :            :  *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
       6                 :            :  *
       7                 :            :  */
       8                 :            : 
       9                 :            : #include <linux/file.h>
      10                 :            : #include <linux/poll.h>
      11                 :            : #include <linux/init.h>
      12                 :            : #include <linux/fs.h>
      13                 :            : #include <linux/sched/signal.h>
      14                 :            : #include <linux/kernel.h>
      15                 :            : #include <linux/slab.h>
      16                 :            : #include <linux/list.h>
      17                 :            : #include <linux/spinlock.h>
      18                 :            : #include <linux/anon_inodes.h>
      19                 :            : #include <linux/syscalls.h>
      20                 :            : #include <linux/export.h>
      21                 :            : #include <linux/kref.h>
      22                 :            : #include <linux/eventfd.h>
      23                 :            : #include <linux/proc_fs.h>
      24                 :            : #include <linux/seq_file.h>
      25                 :            : #include <linux/idr.h>
      26                 :            : 
      27                 :            : DEFINE_PER_CPU(int, eventfd_wake_count);
      28                 :            : 
      29                 :            : static DEFINE_IDA(eventfd_ida);
      30                 :            : 
      31                 :            : struct eventfd_ctx {
      32                 :            :         struct kref kref;
      33                 :            :         wait_queue_head_t wqh;
      34                 :            :         /*
      35                 :            :          * Every time that a write(2) is performed on an eventfd, the
      36                 :            :          * value of the __u64 being written is added to "count" and a
      37                 :            :          * wakeup is performed on "wqh". A read(2) will return the "count"
      38                 :            :          * value to userspace, and will reset "count" to zero. The kernel
      39                 :            :          * side eventfd_signal() also, adds to the "count" counter and
      40                 :            :          * issue a wakeup.
      41                 :            :          */
      42                 :            :         __u64 count;
      43                 :            :         unsigned int flags;
      44                 :            :         int id;
      45                 :            : };
      46                 :            : 
      47                 :            : /**
      48                 :            :  * eventfd_signal - Adds @n to the eventfd counter.
      49                 :            :  * @ctx: [in] Pointer to the eventfd context.
      50                 :            :  * @n: [in] Value of the counter to be added to the eventfd internal counter.
      51                 :            :  *          The value cannot be negative.
      52                 :            :  *
      53                 :            :  * This function is supposed to be called by the kernel in paths that do not
      54                 :            :  * allow sleeping. In this function we allow the counter to reach the ULLONG_MAX
      55                 :            :  * value, and we signal this as overflow condition by returning a EPOLLERR
      56                 :            :  * to poll(2).
      57                 :            :  *
      58                 :            :  * Returns the amount by which the counter was incremented.  This will be less
      59                 :            :  * than @n if the counter has overflowed.
      60                 :            :  */
      61                 :          0 : __u64 eventfd_signal(struct eventfd_ctx *ctx, __u64 n)
      62                 :            : {
      63                 :          0 :         unsigned long flags;
      64                 :            : 
      65                 :            :         /*
      66                 :            :          * Deadlock or stack overflow issues can happen if we recurse here
      67                 :            :          * through waitqueue wakeup handlers. If the caller users potentially
      68                 :            :          * nested waitqueues with custom wakeup handlers, then it should
      69                 :            :          * check eventfd_signal_count() before calling this function. If
      70                 :            :          * it returns true, the eventfd_signal() call should be deferred to a
      71                 :            :          * safe context.
      72                 :            :          */
      73   [ #  #  #  # ]:          0 :         if (WARN_ON_ONCE(this_cpu_read(eventfd_wake_count)))
      74                 :            :                 return 0;
      75                 :            : 
      76                 :          0 :         spin_lock_irqsave(&ctx->wqh.lock, flags);
      77                 :          0 :         this_cpu_inc(eventfd_wake_count);
      78                 :          0 :         if (ULLONG_MAX - ctx->count < n)
      79                 :            :                 n = ULLONG_MAX - ctx->count;
      80                 :          0 :         ctx->count += n;
      81         [ #  # ]:          0 :         if (waitqueue_active(&ctx->wqh))
      82                 :          0 :                 wake_up_locked_poll(&ctx->wqh, EPOLLIN);
      83                 :          0 :         this_cpu_dec(eventfd_wake_count);
      84                 :          0 :         spin_unlock_irqrestore(&ctx->wqh.lock, flags);
      85                 :            : 
      86                 :          0 :         return n;
      87                 :            : }
      88                 :            : EXPORT_SYMBOL_GPL(eventfd_signal);
      89                 :            : 
      90                 :          0 : static void eventfd_free_ctx(struct eventfd_ctx *ctx)
      91                 :            : {
      92         [ #  # ]:          0 :         if (ctx->id >= 0)
      93                 :          0 :                 ida_simple_remove(&eventfd_ida, ctx->id);
      94                 :          0 :         kfree(ctx);
      95                 :          0 : }
      96                 :            : 
      97                 :          0 : static void eventfd_free(struct kref *kref)
      98                 :            : {
      99                 :          0 :         struct eventfd_ctx *ctx = container_of(kref, struct eventfd_ctx, kref);
     100                 :            : 
     101                 :          0 :         eventfd_free_ctx(ctx);
     102                 :          0 : }
     103                 :            : 
     104                 :            : /**
     105                 :            :  * eventfd_ctx_put - Releases a reference to the internal eventfd context.
     106                 :            :  * @ctx: [in] Pointer to eventfd context.
     107                 :            :  *
     108                 :            :  * The eventfd context reference must have been previously acquired either
     109                 :            :  * with eventfd_ctx_fdget() or eventfd_ctx_fileget().
     110                 :            :  */
     111                 :          0 : void eventfd_ctx_put(struct eventfd_ctx *ctx)
     112                 :            : {
     113                 :          0 :         kref_put(&ctx->kref, eventfd_free);
     114                 :          0 : }
     115                 :            : EXPORT_SYMBOL_GPL(eventfd_ctx_put);
     116                 :            : 
     117                 :          0 : static int eventfd_release(struct inode *inode, struct file *file)
     118                 :            : {
     119                 :          0 :         struct eventfd_ctx *ctx = file->private_data;
     120                 :            : 
     121                 :          0 :         wake_up_poll(&ctx->wqh, EPOLLHUP);
     122                 :          0 :         eventfd_ctx_put(ctx);
     123                 :          0 :         return 0;
     124                 :            : }
     125                 :            : 
     126                 :          0 : static __poll_t eventfd_poll(struct file *file, poll_table *wait)
     127                 :            : {
     128                 :          0 :         struct eventfd_ctx *ctx = file->private_data;
     129                 :          0 :         __poll_t events = 0;
     130                 :          0 :         u64 count;
     131                 :            : 
     132         [ #  # ]:          0 :         poll_wait(file, &ctx->wqh, wait);
     133                 :            : 
     134                 :            :         /*
     135                 :            :          * All writes to ctx->count occur within ctx->wqh.lock.  This read
     136                 :            :          * can be done outside ctx->wqh.lock because we know that poll_wait
     137                 :            :          * takes that lock (through add_wait_queue) if our caller will sleep.
     138                 :            :          *
     139                 :            :          * The read _can_ therefore seep into add_wait_queue's critical
     140                 :            :          * section, but cannot move above it!  add_wait_queue's spin_lock acts
     141                 :            :          * as an acquire barrier and ensures that the read be ordered properly
     142                 :            :          * against the writes.  The following CAN happen and is safe:
     143                 :            :          *
     144                 :            :          *     poll                               write
     145                 :            :          *     -----------------                  ------------
     146                 :            :          *     lock ctx->wqh.lock (in poll_wait)
     147                 :            :          *     count = ctx->count
     148                 :            :          *     __add_wait_queue
     149                 :            :          *     unlock ctx->wqh.lock
     150                 :            :          *                                        lock ctx->qwh.lock
     151                 :            :          *                                        ctx->count += n
     152                 :            :          *                                        if (waitqueue_active)
     153                 :            :          *                                          wake_up_locked_poll
     154                 :            :          *                                        unlock ctx->qwh.lock
     155                 :            :          *     eventfd_poll returns 0
     156                 :            :          *
     157                 :            :          * but the following, which would miss a wakeup, cannot happen:
     158                 :            :          *
     159                 :            :          *     poll                               write
     160                 :            :          *     -----------------                  ------------
     161                 :            :          *     count = ctx->count (INVALID!)
     162                 :            :          *                                        lock ctx->qwh.lock
     163                 :            :          *                                        ctx->count += n
     164                 :            :          *                                        **waitqueue_active is false**
     165                 :            :          *                                        **no wake_up_locked_poll!**
     166                 :            :          *                                        unlock ctx->qwh.lock
     167                 :            :          *     lock ctx->wqh.lock (in poll_wait)
     168                 :            :          *     __add_wait_queue
     169                 :            :          *     unlock ctx->wqh.lock
     170                 :            :          *     eventfd_poll returns 0
     171                 :            :          */
     172         [ #  # ]:          0 :         count = READ_ONCE(ctx->count);
     173                 :            : 
     174         [ #  # ]:          0 :         if (count > 0)
     175                 :          0 :                 events |= EPOLLIN;
     176         [ #  # ]:          0 :         if (count == ULLONG_MAX)
     177                 :          0 :                 events |= EPOLLERR;
     178         [ #  # ]:          0 :         if (ULLONG_MAX - 1 > count)
     179                 :          0 :                 events |= EPOLLOUT;
     180                 :            : 
     181                 :          0 :         return events;
     182                 :            : }
     183                 :            : 
     184                 :          0 : static void eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt)
     185                 :            : {
     186                 :          0 :         *cnt = (ctx->flags & EFD_SEMAPHORE) ? 1 : ctx->count;
     187                 :          0 :         ctx->count -= *cnt;
     188                 :            : }
     189                 :            : 
     190                 :            : /**
     191                 :            :  * eventfd_ctx_remove_wait_queue - Read the current counter and removes wait queue.
     192                 :            :  * @ctx: [in] Pointer to eventfd context.
     193                 :            :  * @wait: [in] Wait queue to be removed.
     194                 :            :  * @cnt: [out] Pointer to the 64-bit counter value.
     195                 :            :  *
     196                 :            :  * Returns %0 if successful, or the following error codes:
     197                 :            :  *
     198                 :            :  * -EAGAIN      : The operation would have blocked.
     199                 :            :  *
     200                 :            :  * This is used to atomically remove a wait queue entry from the eventfd wait
     201                 :            :  * queue head, and read/reset the counter value.
     202                 :            :  */
     203                 :          0 : int eventfd_ctx_remove_wait_queue(struct eventfd_ctx *ctx, wait_queue_entry_t *wait,
     204                 :            :                                   __u64 *cnt)
     205                 :            : {
     206                 :          0 :         unsigned long flags;
     207                 :            : 
     208                 :          0 :         spin_lock_irqsave(&ctx->wqh.lock, flags);
     209         [ #  # ]:          0 :         eventfd_ctx_do_read(ctx, cnt);
     210         [ #  # ]:          0 :         __remove_wait_queue(&ctx->wqh, wait);
     211   [ #  #  #  # ]:          0 :         if (*cnt != 0 && waitqueue_active(&ctx->wqh))
     212                 :          0 :                 wake_up_locked_poll(&ctx->wqh, EPOLLOUT);
     213                 :          0 :         spin_unlock_irqrestore(&ctx->wqh.lock, flags);
     214                 :            : 
     215         [ #  # ]:          0 :         return *cnt != 0 ? 0 : -EAGAIN;
     216                 :            : }
     217                 :            : EXPORT_SYMBOL_GPL(eventfd_ctx_remove_wait_queue);
     218                 :            : 
     219                 :          0 : static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
     220                 :            :                             loff_t *ppos)
     221                 :            : {
     222                 :          0 :         struct eventfd_ctx *ctx = file->private_data;
     223                 :          0 :         ssize_t res;
     224                 :          0 :         __u64 ucnt = 0;
     225         [ #  # ]:          0 :         DECLARE_WAITQUEUE(wait, current);
     226                 :            : 
     227         [ #  # ]:          0 :         if (count < sizeof(ucnt))
     228                 :            :                 return -EINVAL;
     229                 :            : 
     230                 :          0 :         spin_lock_irq(&ctx->wqh.lock);
     231                 :          0 :         res = -EAGAIN;
     232         [ #  # ]:          0 :         if (ctx->count > 0)
     233                 :            :                 res = sizeof(ucnt);
     234         [ #  # ]:          0 :         else if (!(file->f_flags & O_NONBLOCK)) {
     235                 :          0 :                 __add_wait_queue(&ctx->wqh, &wait);
     236                 :          0 :                 for (;;) {
     237                 :          0 :                         set_current_state(TASK_INTERRUPTIBLE);
     238         [ #  # ]:          0 :                         if (ctx->count > 0) {
     239                 :            :                                 res = sizeof(ucnt);
     240                 :            :                                 break;
     241                 :            :                         }
     242         [ #  # ]:          0 :                         if (signal_pending(current)) {
     243                 :            :                                 res = -ERESTARTSYS;
     244                 :            :                                 break;
     245                 :            :                         }
     246                 :          0 :                         spin_unlock_irq(&ctx->wqh.lock);
     247                 :          0 :                         schedule();
     248                 :          0 :                         spin_lock_irq(&ctx->wqh.lock);
     249                 :            :                 }
     250                 :          0 :                 __remove_wait_queue(&ctx->wqh, &wait);
     251                 :          0 :                 __set_current_state(TASK_RUNNING);
     252                 :            :         }
     253         [ #  # ]:          0 :         if (likely(res > 0)) {
     254         [ #  # ]:          0 :                 eventfd_ctx_do_read(ctx, &ucnt);
     255         [ #  # ]:          0 :                 if (waitqueue_active(&ctx->wqh))
     256                 :          0 :                         wake_up_locked_poll(&ctx->wqh, EPOLLOUT);
     257                 :            :         }
     258                 :          0 :         spin_unlock_irq(&ctx->wqh.lock);
     259                 :            : 
     260   [ #  #  #  # ]:          0 :         if (res > 0 && put_user(ucnt, (__u64 __user *)buf))
     261                 :          0 :                 return -EFAULT;
     262                 :            : 
     263                 :            :         return res;
     264                 :            : }
     265                 :            : 
     266                 :          0 : static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count,
     267                 :            :                              loff_t *ppos)
     268                 :            : {
     269                 :          0 :         struct eventfd_ctx *ctx = file->private_data;
     270                 :          0 :         ssize_t res;
     271                 :          0 :         __u64 ucnt;
     272         [ #  # ]:          0 :         DECLARE_WAITQUEUE(wait, current);
     273                 :            : 
     274         [ #  # ]:          0 :         if (count < sizeof(ucnt))
     275                 :            :                 return -EINVAL;
     276         [ #  # ]:          0 :         if (copy_from_user(&ucnt, buf, sizeof(ucnt)))
     277                 :            :                 return -EFAULT;
     278         [ #  # ]:          0 :         if (ucnt == ULLONG_MAX)
     279                 :            :                 return -EINVAL;
     280                 :          0 :         spin_lock_irq(&ctx->wqh.lock);
     281                 :          0 :         res = -EAGAIN;
     282         [ #  # ]:          0 :         if (ULLONG_MAX - ctx->count > ucnt)
     283                 :            :                 res = sizeof(ucnt);
     284         [ #  # ]:          0 :         else if (!(file->f_flags & O_NONBLOCK)) {
     285                 :          0 :                 __add_wait_queue(&ctx->wqh, &wait);
     286                 :          0 :                 for (res = 0;;) {
     287                 :          0 :                         set_current_state(TASK_INTERRUPTIBLE);
     288         [ #  # ]:          0 :                         if (ULLONG_MAX - ctx->count > ucnt) {
     289                 :            :                                 res = sizeof(ucnt);
     290                 :            :                                 break;
     291                 :            :                         }
     292         [ #  # ]:          0 :                         if (signal_pending(current)) {
     293                 :            :                                 res = -ERESTARTSYS;
     294                 :            :                                 break;
     295                 :            :                         }
     296                 :          0 :                         spin_unlock_irq(&ctx->wqh.lock);
     297                 :          0 :                         schedule();
     298                 :          0 :                         spin_lock_irq(&ctx->wqh.lock);
     299                 :            :                 }
     300                 :          0 :                 __remove_wait_queue(&ctx->wqh, &wait);
     301                 :          0 :                 __set_current_state(TASK_RUNNING);
     302                 :            :         }
     303         [ #  # ]:          0 :         if (likely(res > 0)) {
     304                 :          0 :                 ctx->count += ucnt;
     305         [ #  # ]:          0 :                 if (waitqueue_active(&ctx->wqh))
     306                 :          0 :                         wake_up_locked_poll(&ctx->wqh, EPOLLIN);
     307                 :            :         }
     308                 :          0 :         spin_unlock_irq(&ctx->wqh.lock);
     309                 :            : 
     310                 :          0 :         return res;
     311                 :            : }
     312                 :            : 
     313                 :            : #ifdef CONFIG_PROC_FS
     314                 :          0 : static void eventfd_show_fdinfo(struct seq_file *m, struct file *f)
     315                 :            : {
     316                 :          0 :         struct eventfd_ctx *ctx = f->private_data;
     317                 :            : 
     318                 :          0 :         spin_lock_irq(&ctx->wqh.lock);
     319                 :          0 :         seq_printf(m, "eventfd-count: %16llx\n",
     320                 :          0 :                    (unsigned long long)ctx->count);
     321                 :          0 :         spin_unlock_irq(&ctx->wqh.lock);
     322                 :          0 :         seq_printf(m, "eventfd-id: %d\n", ctx->id);
     323                 :          0 : }
     324                 :            : #endif
     325                 :            : 
     326                 :            : static const struct file_operations eventfd_fops = {
     327                 :            : #ifdef CONFIG_PROC_FS
     328                 :            :         .show_fdinfo    = eventfd_show_fdinfo,
     329                 :            : #endif
     330                 :            :         .release        = eventfd_release,
     331                 :            :         .poll           = eventfd_poll,
     332                 :            :         .read           = eventfd_read,
     333                 :            :         .write          = eventfd_write,
     334                 :            :         .llseek         = noop_llseek,
     335                 :            : };
     336                 :            : 
     337                 :            : /**
     338                 :            :  * eventfd_fget - Acquire a reference of an eventfd file descriptor.
     339                 :            :  * @fd: [in] Eventfd file descriptor.
     340                 :            :  *
     341                 :            :  * Returns a pointer to the eventfd file structure in case of success, or the
     342                 :            :  * following error pointer:
     343                 :            :  *
     344                 :            :  * -EBADF    : Invalid @fd file descriptor.
     345                 :            :  * -EINVAL   : The @fd file descriptor is not an eventfd file.
     346                 :            :  */
     347                 :          0 : struct file *eventfd_fget(int fd)
     348                 :            : {
     349                 :          0 :         struct file *file;
     350                 :            : 
     351                 :          0 :         file = fget(fd);
     352         [ #  # ]:          0 :         if (!file)
     353                 :            :                 return ERR_PTR(-EBADF);
     354         [ #  # ]:          0 :         if (file->f_op != &eventfd_fops) {
     355                 :          0 :                 fput(file);
     356                 :          0 :                 return ERR_PTR(-EINVAL);
     357                 :            :         }
     358                 :            : 
     359                 :            :         return file;
     360                 :            : }
     361                 :            : EXPORT_SYMBOL_GPL(eventfd_fget);
     362                 :            : 
     363                 :            : /**
     364                 :            :  * eventfd_ctx_fdget - Acquires a reference to the internal eventfd context.
     365                 :            :  * @fd: [in] Eventfd file descriptor.
     366                 :            :  *
     367                 :            :  * Returns a pointer to the internal eventfd context, otherwise the error
     368                 :            :  * pointers returned by the following functions:
     369                 :            :  *
     370                 :            :  * eventfd_fget
     371                 :            :  */
     372                 :          0 : struct eventfd_ctx *eventfd_ctx_fdget(int fd)
     373                 :            : {
     374                 :          0 :         struct eventfd_ctx *ctx;
     375                 :          0 :         struct fd f = fdget(fd);
     376         [ #  # ]:          0 :         if (!f.file)
     377                 :            :                 return ERR_PTR(-EBADF);
     378                 :          0 :         ctx = eventfd_ctx_fileget(f.file);
     379         [ #  # ]:          0 :         fdput(f);
     380                 :            :         return ctx;
     381                 :            : }
     382                 :            : EXPORT_SYMBOL_GPL(eventfd_ctx_fdget);
     383                 :            : 
     384                 :            : /**
     385                 :            :  * eventfd_ctx_fileget - Acquires a reference to the internal eventfd context.
     386                 :            :  * @file: [in] Eventfd file pointer.
     387                 :            :  *
     388                 :            :  * Returns a pointer to the internal eventfd context, otherwise the error
     389                 :            :  * pointer:
     390                 :            :  *
     391                 :            :  * -EINVAL   : The @fd file descriptor is not an eventfd file.
     392                 :            :  */
     393                 :          0 : struct eventfd_ctx *eventfd_ctx_fileget(struct file *file)
     394                 :            : {
     395                 :          0 :         struct eventfd_ctx *ctx;
     396                 :            : 
     397   [ #  #  #  # ]:          0 :         if (file->f_op != &eventfd_fops)
     398                 :            :                 return ERR_PTR(-EINVAL);
     399                 :            : 
     400                 :          0 :         ctx = file->private_data;
     401                 :          0 :         kref_get(&ctx->kref);
     402                 :          0 :         return ctx;
     403                 :            : }
     404                 :            : EXPORT_SYMBOL_GPL(eventfd_ctx_fileget);
     405                 :            : 
     406                 :          0 : static int do_eventfd(unsigned int count, int flags)
     407                 :            : {
     408                 :          0 :         struct eventfd_ctx *ctx;
     409                 :          0 :         int fd;
     410                 :            : 
     411                 :            :         /* Check the EFD_* constants for consistency.  */
     412                 :          0 :         BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC);
     413                 :          0 :         BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK);
     414                 :            : 
     415         [ #  # ]:          0 :         if (flags & ~EFD_FLAGS_SET)
     416                 :            :                 return -EINVAL;
     417                 :            : 
     418                 :          0 :         ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
     419         [ #  # ]:          0 :         if (!ctx)
     420                 :            :                 return -ENOMEM;
     421                 :            : 
     422                 :          0 :         kref_init(&ctx->kref);
     423                 :          0 :         init_waitqueue_head(&ctx->wqh);
     424                 :          0 :         ctx->count = count;
     425                 :          0 :         ctx->flags = flags;
     426                 :          0 :         ctx->id = ida_simple_get(&eventfd_ida, 0, 0, GFP_KERNEL);
     427                 :            : 
     428                 :          0 :         fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx,
     429                 :          0 :                               O_RDWR | (flags & EFD_SHARED_FCNTL_FLAGS));
     430         [ #  # ]:          0 :         if (fd < 0)
     431                 :          0 :                 eventfd_free_ctx(ctx);
     432                 :            : 
     433                 :            :         return fd;
     434                 :            : }
     435                 :            : 
     436                 :          0 : SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
     437                 :            : {
     438                 :          0 :         return do_eventfd(count, flags);
     439                 :            : }
     440                 :            : 
     441                 :          0 : SYSCALL_DEFINE1(eventfd, unsigned int, count)
     442                 :            : {
     443                 :          0 :         return do_eventfd(count, 0);
     444                 :            : }
     445                 :            : 

Generated by: LCOV version 1.14