My understanding - which may be wrong - is that an operation can be in one of three possible states in io_uring:
- Waiting in the submission queue (represented as a submission queue entry)
- In-flight (i.e. the kernel has removed the submission queue entry from the submission queue, but has not yet finished the IO).
- Completed.
Imagine an application which requests millions of IO operations, and has two threads, and an io_uring instance with 32 submission queue entry slots.
One thread is responsible for keeping the submission queue topped up: When the app starts up, this thread fills the submission queue with 32 entries. It then blocks while the submission queue is full. As soon as the submission queue becomes "un-full", it submits another SQE.
The other thread reaps completion queue events.
Is this application likely to overflow the completion queue?
The "Efficient IO with io_uring" PDF suggests that - yes - this app will overflow the completion queue:
Normally an application would ask for a ring of a given size, and the assumption may be that this size corresponds directly to how many requests the application can have pending in the kernel. However, since the sqe lifetime is only that of the actual submission of it, it's possible for the application to drive a higher pending request count than the SQ ring size would indicate. The application must take care not to do so, or it could risk overflowing the CQ ring. By default, the CQ ring is twice the size of the SQ ring. This allows the application some amount of flexibility in managing this aspect, but it doesn't completely remove the need to do so. If the application does violate this restriction, it will be tracked as an overflow condition in the CQ ring.
Does the application have to keep track of the number of operations in-flight? Or is there a simpler way to pause submission to the SQ if the CQ is full?
My understanding is that there are two possible solutions:
Setting the
IORING_SETUP_CQ_NODROP
flag will, to quote Jen Axboe:So, a call to
io_uring_enter()
will return-EBUSY
. Also see theio_uring_queue_init
docs.But, what about the situation where we're using a kernel thread to poll the submission queue (using
IORING_SETUP_SQPOLL
)? In this situation, we're not callingio_uring_enter()
, so we'll never see the-EBUSY
error.I assume the solution here is to call liburing's
io_uring_cq_has_overflow()
before attempting to submit anything to the submission queue?