diff options
Diffstat (limited to 'contrib/libs/liburing/src/queue.c')
| -rw-r--r-- | contrib/libs/liburing/src/queue.c | 68 |
1 files changed, 57 insertions, 11 deletions
diff --git a/contrib/libs/liburing/src/queue.c b/contrib/libs/liburing/src/queue.c index 219a7fc20b7..4dcf8974209 100644 --- a/contrib/libs/liburing/src/queue.c +++ b/contrib/libs/liburing/src/queue.c @@ -102,10 +102,23 @@ static int _io_uring_get_cqe(struct io_uring *ring, if (!need_enter) break; if (looped && data->has_ts) { - struct io_uring_getevents_arg *arg = data->arg; + /* + * When IORING_ENTER_EXT_ARG_REG is set, data->arg + * carries a register-wait offset (an integer), not a + * pointer to io_uring_getevents_arg. Dereferencing it + * as a struct pointer causes a memory access violation. + * For the registered-wait path the kernel enforces the + * timeout, so treat any timeout the same as -ETIME here. + */ + if (data->get_flags & IORING_ENTER_EXT_ARG_REG) { + if (!cqe && !err) + err = -ETIME; + } else { + struct io_uring_getevents_arg *arg = data->arg; - if (!cqe && arg->ts && !err) - err = -ETIME; + if (!cqe && arg->ts && !err) + err = -ETIME; + } break; } @@ -157,24 +170,55 @@ static inline bool io_uring_peek_batch_cqe_(struct io_uring *ring, unsigned *count) { unsigned ready = io_uring_cq_ready(ring); - unsigned shift; unsigned head; unsigned mask; unsigned last; + unsigned nr; if (!ready) return false; - shift = io_uring_cqe_shift(ring); head = *ring->cq.khead; mask = ring->cq.ring_mask; - if (ready < *count) - *count = ready; - last = head + *count; - for (;head != last; head++) - *(cqes++) = &ring->cq.cqes[(head & mask) << shift]; + if (!(ring->flags & IORING_SETUP_CQE_MIXED)) { + unsigned shift = io_uring_cqe_shift(ring); - return true; + if (ready < *count) + *count = ready; + last = head + *count; + for (;head != last; head++) + *(cqes++) = &ring->cq.cqes[(head & mask) << shift]; + + return true; + } + + /* + * For mixed CQE rings, CQEs take up one or two slots, and the kernel + * may post skip entries to pad out the ring at wrap time. Only return + * pointers to real CQEs, with *count denoting the number of CQEs. + */ + last = head + ready; + nr = 0; + while (head != last && nr < *count) { + struct io_uring_cqe *cqe = &ring->cq.cqes[head & mask]; + + if (cqe->flags & IORING_CQE_F_SKIP) { + /* + * A skip entry can only be consumed if it's at the + * current CQ head, stop the batch otherwise. It'll + * be at the head for the next peek. + */ + if (nr) + break; + io_uring_cq_advance(ring, 1); + head++; + continue; + } + head += io_uring_cqe_nr(cqe); + cqes[nr++] = cqe; + } + *count = nr; + return nr != 0; } /* @@ -332,6 +376,8 @@ int io_uring_wait_cqes_min_timeout(struct io_uring *ring, struct __kernel_timespec *ts, unsigned int min_wait_usec, sigset_t *sigmask) { + if (!(ring->features & IORING_FEAT_MIN_TIMEOUT)) + return -EINVAL; return io_uring_wait_cqes_new(ring, cqe_ptr, wait_nr, ts, min_wait_usec, sigmask); } |
