diff options
| author | Jens Axboe <axboe@kernel.dk> | 2025-01-08 11:16:13 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2025-01-17 13:36:24 +0100 |
| commit | 8efff2aa2d95dc437ab67c5b4a9f1d3f367baa10 (patch) | |
| tree | b73be830ea0d915f273a689e733070fa682ece17 /io_uring/io_uring.c | |
| parent | 03753bfacbc6039fce7cc7585287589b87895199 (diff) | |
| download | linux-8efff2aa2d95dc437ab67c5b4a9f1d3f367baa10.tar.gz linux-8efff2aa2d95dc437ab67c5b4a9f1d3f367baa10.tar.bz2 linux-8efff2aa2d95dc437ab67c5b4a9f1d3f367baa10.zip | |
io_uring/eventfd: ensure io_eventfd_signal() defers another RCU period
Commit c9a40292a44e78f71258b8522655bffaf5753bdb upstream.
io_eventfd_do_signal() is invoked from an RCU callback, but when
dropping the reference to the io_ev_fd, it calls io_eventfd_free()
directly if the refcount drops to zero. This isn't correct, as any
potential freeing of the io_ev_fd should be deferred another RCU grace
period.
Just call io_eventfd_put() rather than open-code the dec-and-test and
free, which will correctly defer it another RCU grace period.
Fixes: 21a091b970cd ("io_uring: signal registered eventfd to process deferred task work")
Reported-by: Jann Horn <jannh@google.com>
Cc: stable@vger.kernel.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'io_uring/io_uring.c')
| -rw-r--r-- | io_uring/io_uring.c | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index 0122f220ef0d..c7198fbcf734 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -537,6 +537,13 @@ static __cold void io_queue_deferred(struct io_ring_ctx *ctx) } } +static void io_eventfd_free(struct rcu_head *rcu) +{ + struct io_ev_fd *ev_fd = container_of(rcu, struct io_ev_fd, rcu); + + eventfd_ctx_put(ev_fd->cq_ev_fd); + kfree(ev_fd); +} static void io_eventfd_ops(struct rcu_head *rcu) { @@ -550,10 +557,8 @@ static void io_eventfd_ops(struct rcu_head *rcu) * ordering in a race but if references are 0 we know we have to free * it regardless. */ - if (atomic_dec_and_test(&ev_fd->refs)) { - eventfd_ctx_put(ev_fd->cq_ev_fd); - kfree(ev_fd); - } + if (atomic_dec_and_test(&ev_fd->refs)) + call_rcu(&ev_fd->rcu, io_eventfd_free); } static void io_eventfd_signal(struct io_ring_ctx *ctx) |
