mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/2] io_uring/cancel: cancel all poll matches in one pass
@ 2026-10-30  5:03 Shang En Sim
  2026-10-30  5:03 ` [PATCH 1/2] io_uring/cancel: count all requests that a CANCEL_ALL cancels Shang En Sim
  2026-10-30  5:03 ` [PATCH 2/2] io_uring/poll: cancel all matching requests in one pass Shang En Sim
  0 siblings, 2 replies; 3+ messages in thread
From: Shang En Sim @ 2026-10-30  5:03 UTC (permalink / raw)
  To: Jens Axboe, io-uring; +Cc: Shang En Sim, Peter Zijlstra, linux-kernel

IORING_OP_ASYNC_CANCEL with IORING_ASYNC_CANCEL_ALL cancels poll
requests one at a time, and every lookup starts over at the beginning
of the poll hash. Cancelled requests stay hashed until their task work
runs, so each lookup also walks past the ones already cancelled. One
cancel that matches K of N pending polls costs about K*N/2 visits in a
single io_uring_enter(), with uring_lock held.

Patch 2 makes poll cancel all its matches in one pass, as futex and
waitid already do through io_cancel_remove(). Patch 1 is a prerequisite
and a fix on its own: __io_async_cancel() counts each io_try_cancel()
call as one, so CANCEL_ALL on futex or waitid requests reports 1 no
matter how many it cancelled. Patch 2 needs it to keep the poll count
right.

Reproducer, 80000 polls on one eventfd and a single CANCEL_FD|ALL:

  #include <liburing.h>
  #include <poll.h>
  #include <sys/eventfd.h>

  int main(void)
  {
  	struct io_uring ring;
  	int fd = eventfd(0, 0), i;

  	io_uring_queue_init(4096, &ring, 0);
  	for (i = 0; i < 80000; i++) {
  		struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);

  		if (!sqe) {
  			io_uring_submit(&ring);
  			sqe = io_uring_get_sqe(&ring);
  		}
  		io_uring_prep_poll_add(sqe, fd, POLLIN);
  	}
  	io_uring_prep_cancel_fd(io_uring_get_sqe(&ring), fd,
  				IORING_ASYNC_CANCEL_ALL);
  	io_uring_submit(&ring);
  	return 0;
  }

In a 4 vCPU KVM guest, "time ./repro" takes 17.06s of system time on
next-20261029 (lazy preemption) and 0.02s with these patches. On
v6.18.59 with voluntary preemption it takes 36.24s, and the soft lockup
watchdog fires during the cancel.

Testing, on next-20261029 and v6.18.59: liburing's cancel tests
(poll-cancel-all, poll-cancel, poll-cancel-ton, cancel-fd-userdata,
io-cancel, sync-cancel, cancel-race, futex, waitid), plus three new
tests that I'll send to liburing separately: a futex CANCEL_ALL count
(fails before patch 1), and poll CANCEL_ALL by user_data alone and with
1000 polls on one fd. All pass, except waitid's pidfd test on
v6.18.59, which fails with and without these patches. Not tested:
lockdep, KASAN, and SQPOLL or DEFER_TASKRUN rings for the new cases.


Shang En Sim (2):
  io_uring/cancel: count all requests that a CANCEL_ALL cancels
  io_uring/poll: cancel all matching requests in one pass

 io_uring/cancel.c |  3 ++-
 io_uring/poll.c   | 39 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 39 insertions(+), 3 deletions(-)


base-commit: 70866cfa169d5ee149364267289e71d50f9a7ae9
-- 
2.56.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-10-30  5:04 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-30  5:03 [PATCH 0/2] io_uring/cancel: cancel all poll matches in one pass Shang En Sim
2026-10-30  5:03 ` [PATCH 1/2] io_uring/cancel: count all requests that a CANCEL_ALL cancels Shang En Sim
2026-10-30  5:03 ` [PATCH 2/2] io_uring/poll: cancel all matching requests in one pass Shang En Sim

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®