While eventfd ->read() callback was replaced by ->read_iter() recently by
commit 12aceb89b0bc ("eventfd: convert to f_op->read_iter()"), ->write()
was not replaced.

Convert also ->write() to ->write_iter() to make the interface more
consistent and allow non-blocking writes from e.g. io_uring. Also
reorganize the code and return value handling in a similar way as it was
done in eventfd_read().

v2: different reasoning in commit message (no code change)

Signed-off-by: Michal Kubecek <mkube...@suse.cz>
---
 fs/eventfd.c | 43 +++++++++++++++++++++----------------------
 1 file changed, 21 insertions(+), 22 deletions(-)

diff --git a/fs/eventfd.c b/fs/eventfd.c
index df466ef81ddd..35973d216847 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -261,35 +261,36 @@ static ssize_t eventfd_read(struct kiocb *iocb, struct 
iov_iter *to)
        return sizeof(ucnt);
 }
 
-static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t 
count,
-                            loff_t *ppos)
+static ssize_t eventfd_write(struct kiocb *iocb, struct iov_iter *from)
 {
+       struct file *file = iocb->ki_filp;
        struct eventfd_ctx *ctx = file->private_data;
-       ssize_t res;
        __u64 ucnt;
        DECLARE_WAITQUEUE(wait, current);
 
-       if (count < sizeof(ucnt))
+       if (iov_iter_count(from) < sizeof(ucnt))
                return -EINVAL;
-       if (copy_from_user(&ucnt, buf, sizeof(ucnt)))
+       if (unlikely(!copy_from_iter_full(&ucnt, sizeof(ucnt), from)))
                return -EFAULT;
        if (ucnt == ULLONG_MAX)
                return -EINVAL;
        spin_lock_irq(&ctx->wqh.lock);
-       res = -EAGAIN;
-       if (ULLONG_MAX - ctx->count > ucnt)
-               res = sizeof(ucnt);
-       else if (!(file->f_flags & O_NONBLOCK)) {
+       if (ULLONG_MAX - ctx->count <= ucnt) {
+               if ((file->f_flags & O_NONBLOCK) ||
+                   (iocb->ki_flags & IOCB_NOWAIT)) {
+                       spin_unlock_irq(&ctx->wqh.lock);
+                       return -EAGAIN;
+               }
                __add_wait_queue(&ctx->wqh, &wait);
-               for (res = 0;;) {
+               for (;;) {
                        set_current_state(TASK_INTERRUPTIBLE);
-                       if (ULLONG_MAX - ctx->count > ucnt) {
-                               res = sizeof(ucnt);
+                       if (ULLONG_MAX - ctx->count > ucnt)
                                break;
-                       }
                        if (signal_pending(current)) {
-                               res = -ERESTARTSYS;
-                               break;
+                               __remove_wait_queue(&ctx->wqh, &wait);
+                               __set_current_state(TASK_RUNNING);
+                               spin_unlock_irq(&ctx->wqh.lock);
+                               return -ERESTARTSYS;
                        }
                        spin_unlock_irq(&ctx->wqh.lock);
                        schedule();
@@ -298,14 +299,12 @@ static ssize_t eventfd_write(struct file *file, const 
char __user *buf, size_t c
                __remove_wait_queue(&ctx->wqh, &wait);
                __set_current_state(TASK_RUNNING);
        }
-       if (likely(res > 0)) {
-               ctx->count += ucnt;
-               if (waitqueue_active(&ctx->wqh))
-                       wake_up_locked_poll(&ctx->wqh, EPOLLIN);
-       }
+       ctx->count += ucnt;
+       if (waitqueue_active(&ctx->wqh))
+               wake_up_locked_poll(&ctx->wqh, EPOLLIN);
        spin_unlock_irq(&ctx->wqh.lock);
 
-       return res;
+       return sizeof(ucnt);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -328,7 +327,7 @@ static const struct file_operations eventfd_fops = {
        .release        = eventfd_release,
        .poll           = eventfd_poll,
        .read_iter      = eventfd_read,
-       .write          = eventfd_write,
+       .write_iter     = eventfd_write,
        .llseek         = noop_llseek,
 };
 
-- 
2.29.2

Reply via email to