This is a note to let you know that I've just added the patch titled io_uring: pass in EPOLL_URING_WAKE for eventfd signaling and wakeups to the 6.1-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: io_uring-pass-in-epoll_uring_wake-for-eventfd-signaling-and-wakeups.patch and it can be found in the queue-6.1 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From 4464853277d0ccdb9914608dd1332f0fa2f9846f Mon Sep 17 00:00:00 2001 From: Jens Axboe <axboe@xxxxxxxxx> Date: Sun, 20 Nov 2022 10:18:45 -0700 Subject: io_uring: pass in EPOLL_URING_WAKE for eventfd signaling and wakeups From: Jens Axboe <axboe@xxxxxxxxx> commit 4464853277d0ccdb9914608dd1332f0fa2f9846f upstream. Pass in EPOLL_URING_WAKE when signaling eventfd or doing poll related wakups, so that we can check for a circular event dependency between eventfd and epoll. If this flag is set when our wakeup handlers are called, then we know we have a dependency that needs to terminate multishot requests. eventfd and epoll are the only such possible dependencies. Cc: stable@xxxxxxxxxxxxxxx # 6.0 Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- io_uring/io_uring.c | 4 ++-- io_uring/io_uring.h | 15 +++++++++++---- io_uring/poll.c | 8 ++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -495,7 +495,7 @@ static void io_eventfd_ops(struct rcu_he int ops = atomic_xchg(&ev_fd->ops, 0); if (ops & BIT(IO_EVENTFD_OP_SIGNAL_BIT)) - eventfd_signal(ev_fd->cq_ev_fd, 1); + eventfd_signal_mask(ev_fd->cq_ev_fd, 1, EPOLL_URING_WAKE); /* IO_EVENTFD_OP_FREE_BIT may not be set here depending on callback * ordering in a race but if references are 0 we know we have to free @@ -531,7 +531,7 @@ static void io_eventfd_signal(struct io_ goto out; if (likely(eventfd_signal_allowed())) { - eventfd_signal(ev_fd->cq_ev_fd, 1); + eventfd_signal_mask(ev_fd->cq_ev_fd, 1, EPOLL_URING_WAKE); } else { atomic_inc(&ev_fd->refs); if (!atomic_fetch_or(BIT(IO_EVENTFD_OP_SIGNAL_BIT), &ev_fd->ops)) --- a/io_uring/io_uring.h +++ b/io_uring/io_uring.h @@ -4,6 +4,7 @@ #include <linux/errno.h> #include <linux/lockdep.h> #include <linux/io_uring_types.h> +#include <uapi/linux/eventpoll.h> #include "io-wq.h" #include "slist.h" #include "filetable.h" @@ -207,12 +208,18 @@ static inline void io_commit_cqring(stru static inline void __io_cqring_wake(struct io_ring_ctx *ctx) { /* - * wake_up_all() may seem excessive, but io_wake_function() and - * io_should_wake() handle the termination of the loop and only - * wake as many waiters as we need to. + * Trigger waitqueue handler on all waiters on our waitqueue. This + * won't necessarily wake up all the tasks, io_should_wake() will make + * that decision. + * + * Pass in EPOLLIN|EPOLL_URING_WAKE as the poll wakeup key. The latter + * set in the mask so that if we recurse back into our own poll + * waitqueue handlers, we know we have a dependency between eventfd or + * epoll and should terminate multishot poll at that point. */ if (waitqueue_active(&ctx->cq_wait)) - wake_up_all(&ctx->cq_wait); + __wake_up(&ctx->cq_wait, TASK_NORMAL, 0, + poll_to_key(EPOLL_URING_WAKE | EPOLLIN)); } static inline void io_cqring_wake(struct io_ring_ctx *ctx) --- a/io_uring/poll.c +++ b/io_uring/poll.c @@ -429,6 +429,14 @@ static int io_poll_wake(struct wait_queu return 0; if (io_poll_get_ownership(req)) { + /* + * If we trigger a multishot poll off our own wakeup path, + * disable multishot as there is a circular dependency between + * CQ posting and triggering the event. + */ + if (mask & EPOLL_URING_WAKE) + poll->events |= EPOLLONESHOT; + /* optional, saves extra locking for removal in tw handler */ if (mask && poll->events & EPOLLONESHOT) { list_del_init(&poll->wait.entry); Patches currently in stable-queue which might be from axboe@xxxxxxxxx are queue-6.1/dm-make-sure-create-and-remove-dm-device-won-t-race-.patch queue-6.1/block-factor-out-a-blk_debugfs_remove-helper.patch queue-6.1/relay-fix-type-mismatch-when-allocating-memory-in-re.patch queue-6.1/eventfd-change-int-to-__u64-in-eventfd_signal-ifndef.patch queue-6.1/loop-fix-the-max_loop-commandline-argument-treatment-when-it-is-set-to-0.patch queue-6.1/blk-crypto-pass-a-gendisk-to-blk_crypto_sysfs_-un-re.patch queue-6.1/io_uring-pass-in-epoll_uring_wake-for-eventfd-signaling-and-wakeups.patch queue-6.1/blk-mq-fix-possible-memleak-when-register-hctx-faile.patch queue-6.1/io_uring-net-introduce-ioring_send_zc_report_usage-flag.patch queue-6.1/io_uring-net-fix-cleanup-after-recycle.patch queue-6.1/io_uring-dont-remove-file-from-msg_ring-reqs.patch queue-6.1/block-mark-blk_put_queue-as-potentially-blocking.patch queue-6.1/dm-track-per-add_disk-holder-relations-in-dm.patch queue-6.1/blk-iolatency-fix-memory-leak-on-add_disk-failures.patch queue-6.1/io_uring-protect-cq_timeouts-with-timeout_lock.patch queue-6.1/block-fix-error-unwinding-in-blk_register_queue.patch queue-6.1/drbd-remove-call-to-memset-before-free-device-resour.patch queue-6.1/dm-cleanup-close_table_device.patch queue-6.1/blktrace-fix-output-non-blktrace-event-when-blk_clas.patch queue-6.1/drbd-use-blk_queue_max_discard_sectors-helper.patch queue-6.1/block-fix-use-after-free-of-q-q_usage_counter.patch queue-6.1/blk-mq-move-the-srcu_struct-used-for-quiescing-to-th.patch queue-6.1/drbd-destroy-workqueue-when-drbd-device-was-freed.patch queue-6.1/block-bfq-fix-possible-uaf-for-bfqq-bic.patch queue-6.1/io_uring-add-completion-locking-for-iopoll.patch queue-6.1/block-untangle-request_queue-refcounting-from-sysfs.patch queue-6.1/block-clear-slave_dir-when-dropping-the-main-slave_d.patch queue-6.1/io_uring-net-ensure-compat-import-handlers-clear-free_iov.patch queue-6.1/bfq-fix-waker_bfqq-inconsistency-crash.patch queue-6.1/blk-mq-avoid-double-queue_rq-because-of-early-timeou.patch queue-6.1/dm-cleanup-open_table_device.patch queue-6.1/io_uring-improve-io_double_lock_ctx-fail-handling.patch