summaryrefslogtreecommitdiffstats
path: root/contrib/libs/liburing/src/queue.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/libs/liburing/src/queue.c')
-rw-r--r--contrib/libs/liburing/src/queue.c68
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);
}