LCOV - code coverage report
Current view: top level - fs - eventfd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 62 113 54.9 %
Date: 2014-02-18 Functions: 10 17 58.8 %
Branches: 38 73 52.1 %

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

Generated by: LCOV version 1.9