| 60 | }; |
| 61 | |
| 62 | static int _io_uring_get_cqe(struct io_uring *ring, |
| 63 | struct io_uring_cqe **cqe_ptr, |
| 64 | struct get_data *data) |
| 65 | { |
| 66 | struct io_uring_cqe *cqe = NULL; |
| 67 | bool looped = false; |
| 68 | int err = 0; |
| 69 | |
| 70 | do { |
| 71 | bool need_enter = false; |
| 72 | unsigned flags = ring_enter_flags(ring); |
| 73 | unsigned nr_available; |
| 74 | int ret; |
| 75 | |
| 76 | ret = __io_uring_peek_cqe(ring, &cqe, &nr_available); |
| 77 | if (ret) { |
| 78 | if (!err) |
| 79 | err = ret; |
| 80 | break; |
| 81 | } |
| 82 | if (!cqe && !data->wait_nr && !data->submit) { |
| 83 | /* |
| 84 | * If we already looped once, we already entered |
| 85 | * the kernel. Since there's nothing to submit or |
| 86 | * wait for, don't keep retrying. |
| 87 | */ |
| 88 | if (looped || !cq_ring_needs_enter(ring)) { |
| 89 | if (!err) |
| 90 | err = -EAGAIN; |
| 91 | break; |
| 92 | } |
| 93 | need_enter = true; |
| 94 | } |
| 95 | if (data->wait_nr > nr_available || need_enter) { |
| 96 | flags |= IORING_ENTER_GETEVENTS | data->get_flags; |
| 97 | need_enter = true; |
| 98 | } |
| 99 | if (sq_ring_needs_enter(ring, data->submit, &flags)) |
| 100 | need_enter = true; |
| 101 | if (!need_enter) |
| 102 | break; |
| 103 | if (looped && data->has_ts) { |
| 104 | /* |
| 105 | * When IORING_ENTER_EXT_ARG_REG is set, data->arg |
| 106 | * carries a register-wait offset (an integer), not a |
| 107 | * pointer to io_uring_getevents_arg. Dereferencing it |
| 108 | * as a struct pointer causes a memory access violation. |
| 109 | * For the registered-wait path the kernel enforces the |
| 110 | * timeout, so treat any timeout the same as -ETIME here. |
| 111 | */ |
| 112 | if (data->get_flags & IORING_ENTER_EXT_ARG_REG) { |
| 113 | if (!cqe && !err) |
| 114 | err = -ETIME; |
| 115 | } else { |
| 116 | struct io_uring_getevents_arg *arg = data->arg; |
| 117 | |
| 118 | if (!cqe && arg->ts && !err) |
| 119 | err = -ETIME; |
no test coverage detected