Skip to content

Commit 6d5f904

Browse files
Xiaoguang Wangaxboe
authored andcommitted
io_uring: export cq overflow status to userspace
For those applications which are not willing to use io_uring_enter() to reap and handle cqes, they may completely rely on liburing's io_uring_peek_cqe(), but if cq ring has overflowed, currently because io_uring_peek_cqe() is not aware of this overflow, it won't enter kernel to flush cqes, below test program can reveal this bug: static void test_cq_overflow(struct io_uring *ring) { struct io_uring_cqe *cqe; struct io_uring_sqe *sqe; int issued = 0; int ret = 0; do { sqe = io_uring_get_sqe(ring); if (!sqe) { fprintf(stderr, "get sqe failed\n"); break;; } ret = io_uring_submit(ring); if (ret <= 0) { if (ret != -EBUSY) fprintf(stderr, "sqe submit failed: %d\n", ret); break; } issued++; } while (ret > 0); assert(ret == -EBUSY); printf("issued requests: %d\n", issued); while (issued) { ret = io_uring_peek_cqe(ring, &cqe); if (ret) { if (ret != -EAGAIN) { fprintf(stderr, "peek completion failed: %s\n", strerror(ret)); break; } printf("left requets: %d\n", issued); continue; } io_uring_cqe_seen(ring, cqe); issued--; printf("left requets: %d\n", issued); } } int main(int argc, char *argv[]) { int ret; struct io_uring ring; ret = io_uring_queue_init(16, &ring, 0); if (ret) { fprintf(stderr, "ring setup failed: %d\n", ret); return 1; } test_cq_overflow(&ring); return 0; } To fix this issue, export cq overflow status to userspace by adding new IORING_SQ_CQ_OVERFLOW flag, then helper functions() in liburing, such as io_uring_peek_cqe, can be aware of this cq overflow and do flush accordingly. Signed-off-by: Xiaoguang Wang <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent b7db41c commit 6d5f904

File tree

2 files changed

+10
-2
lines changed

2 files changed

+10
-2
lines changed

fs/io_uring.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,7 @@ static bool io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force)
12741274
if (cqe) {
12751275
clear_bit(0, &ctx->sq_check_overflow);
12761276
clear_bit(0, &ctx->cq_check_overflow);
1277+
ctx->rings->sq_flags &= ~IORING_SQ_CQ_OVERFLOW;
12771278
}
12781279
spin_unlock_irqrestore(&ctx->completion_lock, flags);
12791280
io_cqring_ev_posted(ctx);
@@ -1311,6 +1312,7 @@ static void __io_cqring_fill_event(struct io_kiocb *req, long res, long cflags)
13111312
if (list_empty(&ctx->cq_overflow_list)) {
13121313
set_bit(0, &ctx->sq_check_overflow);
13131314
set_bit(0, &ctx->cq_check_overflow);
1315+
ctx->rings->sq_flags |= IORING_SQ_CQ_OVERFLOW;
13141316
}
13151317
req->flags |= REQ_F_OVERFLOW;
13161318
refcount_inc(&req->refs);
@@ -6080,9 +6082,9 @@ static int io_sq_thread(void *data)
60806082
}
60816083

60826084
/* Tell userspace we may need a wakeup call */
6085+
spin_lock_irq(&ctx->completion_lock);
60836086
ctx->rings->sq_flags |= IORING_SQ_NEED_WAKEUP;
6084-
/* make sure to read SQ tail after writing flags */
6085-
smp_mb();
6087+
spin_unlock_irq(&ctx->completion_lock);
60866088

60876089
to_submit = io_sqring_entries(ctx);
60886090
if (!to_submit || ret == -EBUSY) {
@@ -6100,13 +6102,17 @@ static int io_sq_thread(void *data)
61006102
schedule();
61016103
finish_wait(&ctx->sqo_wait, &wait);
61026104

6105+
spin_lock_irq(&ctx->completion_lock);
61036106
ctx->rings->sq_flags &= ~IORING_SQ_NEED_WAKEUP;
6107+
spin_unlock_irq(&ctx->completion_lock);
61046108
ret = 0;
61056109
continue;
61066110
}
61076111
finish_wait(&ctx->sqo_wait, &wait);
61086112

6113+
spin_lock_irq(&ctx->completion_lock);
61096114
ctx->rings->sq_flags &= ~IORING_SQ_NEED_WAKEUP;
6115+
spin_unlock_irq(&ctx->completion_lock);
61106116
}
61116117

61126118
mutex_lock(&ctx->uring_lock);
@@ -7488,6 +7494,7 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx,
74887494
if (list_empty(&ctx->cq_overflow_list)) {
74897495
clear_bit(0, &ctx->sq_check_overflow);
74907496
clear_bit(0, &ctx->cq_check_overflow);
7497+
ctx->rings->sq_flags &= ~IORING_SQ_CQ_OVERFLOW;
74917498
}
74927499
spin_unlock_irq(&ctx->completion_lock);
74937500

include/uapi/linux/io_uring.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ struct io_sqring_offsets {
197197
* sq_ring->flags
198198
*/
199199
#define IORING_SQ_NEED_WAKEUP (1U << 0) /* needs io_uring_enter wakeup */
200+
#define IORING_SQ_CQ_OVERFLOW (1U << 1) /* CQ ring is overflown */
200201

201202
struct io_cqring_offsets {
202203
__u32 head;

0 commit comments

Comments
 (0)