lkml.org 
[lkml]   [2022]   [Oct]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 6.0 545/862] eventfd: guard wake_up in eventfd fs calls as well
    Date
    From: Dylan Yudaken <dylany@fb.com>

    [ Upstream commit 9f0deaa12d832f488500a5afe9b912e9b3cfc432 ]

    Guard wakeups that the user can trigger, and that may end up triggering a
    call back into eventfd_signal. This is in addition to the current approach
    that only guards in eventfd_signal.

    Rename in_eventfd_signal -> in_eventfd at the same time to reflect this.

    Without this there would be a deadlock in the following code using libaio:

    int main()
    {
    struct io_context *ctx = NULL;
    struct iocb iocb;
    struct iocb *iocbs[] = { &iocb };
    int evfd;
    uint64_t val = 1;

    evfd = eventfd(0, EFD_CLOEXEC);
    assert(!io_setup(2, &ctx));
    io_prep_poll(&iocb, evfd, POLLIN);
    io_set_eventfd(&iocb, evfd);
    assert(1 == io_submit(ctx, 1, iocbs));
    write(evfd, &val, 8);
    }

    Signed-off-by: Dylan Yudaken <dylany@fb.com>
    Reviewed-by: Jens Axboe <axboe@kernel.dk>
    Link: https://lore.kernel.org/r/20220816135959.1490641-1-dylany@fb.com
    Signed-off-by: Jens Axboe <axboe@kernel.dk>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    fs/eventfd.c | 10 +++++++---
    include/linux/eventfd.h | 2 +-
    include/linux/sched.h | 2 +-
    3 files changed, 9 insertions(+), 5 deletions(-)

    --- a/fs/eventfd.c
    +++ b/fs/eventfd.c
    @@ -69,17 +69,17 @@ __u64 eventfd_signal(struct eventfd_ctx
    * it returns false, the eventfd_signal() call should be deferred to a
    * safe context.
    */
    - if (WARN_ON_ONCE(current->in_eventfd_signal))
    + if (WARN_ON_ONCE(current->in_eventfd))
    return 0;

    spin_lock_irqsave(&ctx->wqh.lock, flags);
    - current->in_eventfd_signal = 1;
    + current->in_eventfd = 1;
    if (ULLONG_MAX - ctx->count < n)
    n = ULLONG_MAX - ctx->count;
    ctx->count += n;
    if (waitqueue_active(&ctx->wqh))
    wake_up_locked_poll(&ctx->wqh, EPOLLIN);
    - current->in_eventfd_signal = 0;
    + current->in_eventfd = 0;
    spin_unlock_irqrestore(&ctx->wqh.lock, flags);

    return n;
    @@ -253,8 +253,10 @@ static ssize_t eventfd_read(struct kiocb
    __set_current_state(TASK_RUNNING);
    }
    eventfd_ctx_do_read(ctx, &ucnt);
    + current->in_eventfd = 1;
    if (waitqueue_active(&ctx->wqh))
    wake_up_locked_poll(&ctx->wqh, EPOLLOUT);
    + current->in_eventfd = 0;
    spin_unlock_irq(&ctx->wqh.lock);
    if (unlikely(copy_to_iter(&ucnt, sizeof(ucnt), to) != sizeof(ucnt)))
    return -EFAULT;
    @@ -301,8 +303,10 @@ static ssize_t eventfd_write(struct file
    }
    if (likely(res > 0)) {
    ctx->count += ucnt;
    + current->in_eventfd = 1;
    if (waitqueue_active(&ctx->wqh))
    wake_up_locked_poll(&ctx->wqh, EPOLLIN);
    + current->in_eventfd = 0;
    }
    spin_unlock_irq(&ctx->wqh.lock);

    --- a/include/linux/eventfd.h
    +++ b/include/linux/eventfd.h
    @@ -46,7 +46,7 @@ void eventfd_ctx_do_read(struct eventfd_

    static inline bool eventfd_signal_allowed(void)
    {
    - return !current->in_eventfd_signal;
    + return !current->in_eventfd;
    }

    #else /* CONFIG_EVENTFD */
    --- a/include/linux/sched.h
    +++ b/include/linux/sched.h
    @@ -936,7 +936,7 @@ struct task_struct {
    #endif
    #ifdef CONFIG_EVENTFD
    /* Recursion prevention for eventfd_signal() */
    - unsigned in_eventfd_signal:1;
    + unsigned in_eventfd:1;
    #endif
    #ifdef CONFIG_IOMMU_SVA
    unsigned pasid_activated:1;

    \
     
     \ /
      Last update: 2022-10-19 14:22    [W:4.024 / U:0.164 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site