Since the CQ ring dump was changed to deal with IORING_SETUP_CQE_MIXED, a 32b CQE is taken to occupy two entries of the ring. That is how it works for mixed rings. With IORING_SETUP_CQE32 each entry has twice the size: head and tail count 32b CQEs, and entry n is found at cqes[n << 1]. For such rings the dump reads cqes[n], and skips every other entry. It shows half of the pending CQEs at best, and what it shows is taken from the wrong place unless the head happens to be at the start of the ring. The extra data of the last entry isn't shown at all, as the check that keeps the dump of a mixed ring from reading beyond the array is applied to these rings as well. Fixes: 82ceb7fcc5ff ("io_uring/fdinfo: handle mixed sized CQEs") Assisted-by: LLM Signed-off-by: Josef Bacik --- io_uring/fdinfo.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/io_uring/fdinfo.c b/io_uring/fdinfo.c index c362f3a81bdc..46e64b041360 100644 --- a/io_uring/fdinfo.c +++ b/io_uring/fdinfo.c @@ -154,20 +154,26 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m) cq_entries = min(cq_tail - cq_head, ctx->cq_entries); for (i = 0; i < cq_entries; i++) { struct io_uring_cqe *cqe; - bool cqe32 = false; + bool cqe32 = false, two_entries = false; bool is_last_cqarray_slot = (cq_head & cq_mask) == cq_mask; - cqe = &r->cqes[(cq_head & cq_mask)]; - /* - * Userspace can manipulate the last cqarray slot to have - * IORING_CQE_F_32 set, which would cause the second half of - * that CQE to be read out of bounds. - * Ignore the flag for the last cqarray slot, which can't - * legitimately have the flag set. - */ - if ((cqe->flags & IORING_CQE_F_32 || ctx->flags & IORING_SETUP_CQE32) && - !is_last_cqarray_slot) + if (ctx->flags & IORING_SETUP_CQE32) { + /* all entries have twice the size */ + cqe = &r->cqes[(cq_head & cq_mask) << 1]; cqe32 = true; + } else { + cqe = &r->cqes[(cq_head & cq_mask)]; + /* + * Userspace can manipulate the last cqarray slot to + * have IORING_CQE_F_32 set, which would cause the second + * half of that CQE to be read out of bounds. + * Ignore the flag for the last cqarray slot, which can't + * legitimately have the flag set. + */ + two_entries = (cqe->flags & IORING_CQE_F_32) && + !is_last_cqarray_slot; + cqe32 = two_entries; + } seq_printf(m, "%5u: user_data:%llu, res:%d, flags:%x", cq_head & cq_mask, cqe->user_data, cqe->res, cqe->flags); @@ -176,7 +182,7 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m) cqe->big_cqe[0], cqe->big_cqe[1]); seq_printf(m, "\n"); cq_head++; - if (cqe32) { + if (two_entries) { cq_head++; i++; } -- 2.55.0