1*73fd282eSStefan Hajnoczi /* SPDX-License-Identifier: GPL-2.0-or-later */ 2*73fd282eSStefan Hajnoczi /* 3*73fd282eSStefan Hajnoczi * Linux io_uring file descriptor monitoring 4*73fd282eSStefan Hajnoczi * 5*73fd282eSStefan Hajnoczi * The Linux io_uring API supports file descriptor monitoring with a few 6*73fd282eSStefan Hajnoczi * advantages over existing APIs like poll(2) and epoll(7): 7*73fd282eSStefan Hajnoczi * 8*73fd282eSStefan Hajnoczi * 1. Userspace polling of events is possible because the completion queue (cq 9*73fd282eSStefan Hajnoczi * ring) is shared between the kernel and userspace. This allows 10*73fd282eSStefan Hajnoczi * applications that rely on userspace polling to also monitor file 11*73fd282eSStefan Hajnoczi * descriptors in the same userspace polling loop. 12*73fd282eSStefan Hajnoczi * 13*73fd282eSStefan Hajnoczi * 2. Submission and completion is batched and done together in a single system 14*73fd282eSStefan Hajnoczi * call. This minimizes the number of system calls. 15*73fd282eSStefan Hajnoczi * 16*73fd282eSStefan Hajnoczi * 3. File descriptor monitoring is O(1) like epoll(7) so it scales better than 17*73fd282eSStefan Hajnoczi * poll(2). 18*73fd282eSStefan Hajnoczi * 19*73fd282eSStefan Hajnoczi * 4. Nanosecond timeouts are supported so it requires fewer syscalls than 20*73fd282eSStefan Hajnoczi * epoll(7). 21*73fd282eSStefan Hajnoczi * 22*73fd282eSStefan Hajnoczi * This code only monitors file descriptors and does not do asynchronous disk 23*73fd282eSStefan Hajnoczi * I/O. Implementing disk I/O efficiently has other requirements and should 24*73fd282eSStefan Hajnoczi * use a separate io_uring so it does not make sense to unify the code. 25*73fd282eSStefan Hajnoczi * 26*73fd282eSStefan Hajnoczi * File descriptor monitoring is implemented using the following operations: 27*73fd282eSStefan Hajnoczi * 28*73fd282eSStefan Hajnoczi * 1. IORING_OP_POLL_ADD - adds a file descriptor to be monitored. 29*73fd282eSStefan Hajnoczi * 2. IORING_OP_POLL_REMOVE - removes a file descriptor being monitored. When 30*73fd282eSStefan Hajnoczi * the poll mask changes for a file descriptor it is first removed and then 31*73fd282eSStefan Hajnoczi * re-added with the new poll mask, so this operation is also used as part 32*73fd282eSStefan Hajnoczi * of modifying an existing monitored file descriptor. 33*73fd282eSStefan Hajnoczi * 3. IORING_OP_TIMEOUT - added every time a blocking syscall is made to wait 34*73fd282eSStefan Hajnoczi * for events. This operation self-cancels if another event completes 35*73fd282eSStefan Hajnoczi * before the timeout. 36*73fd282eSStefan Hajnoczi * 37*73fd282eSStefan Hajnoczi * io_uring calls the submission queue the "sq ring" and the completion queue 38*73fd282eSStefan Hajnoczi * the "cq ring". Ring entries are called "sqe" and "cqe", respectively. 39*73fd282eSStefan Hajnoczi * 40*73fd282eSStefan Hajnoczi * The code is structured so that sq/cq rings are only modified within 41*73fd282eSStefan Hajnoczi * fdmon_io_uring_wait(). Changes to AioHandlers are made by enqueuing them on 42*73fd282eSStefan Hajnoczi * ctx->submit_list so that fdmon_io_uring_wait() can submit IORING_OP_POLL_ADD 43*73fd282eSStefan Hajnoczi * and/or IORING_OP_POLL_REMOVE sqes for them. 44*73fd282eSStefan Hajnoczi */ 45*73fd282eSStefan Hajnoczi 46*73fd282eSStefan Hajnoczi #include "qemu/osdep.h" 47*73fd282eSStefan Hajnoczi #include <poll.h> 48*73fd282eSStefan Hajnoczi #include "qemu/rcu_queue.h" 49*73fd282eSStefan Hajnoczi #include "aio-posix.h" 50*73fd282eSStefan Hajnoczi 51*73fd282eSStefan Hajnoczi enum { 52*73fd282eSStefan Hajnoczi FDMON_IO_URING_ENTRIES = 128, /* sq/cq ring size */ 53*73fd282eSStefan Hajnoczi 54*73fd282eSStefan Hajnoczi /* AioHandler::flags */ 55*73fd282eSStefan Hajnoczi FDMON_IO_URING_PENDING = (1 << 0), 56*73fd282eSStefan Hajnoczi FDMON_IO_URING_ADD = (1 << 1), 57*73fd282eSStefan Hajnoczi FDMON_IO_URING_REMOVE = (1 << 2), 58*73fd282eSStefan Hajnoczi }; 59*73fd282eSStefan Hajnoczi 60*73fd282eSStefan Hajnoczi static inline int poll_events_from_pfd(int pfd_events) 61*73fd282eSStefan Hajnoczi { 62*73fd282eSStefan Hajnoczi return (pfd_events & G_IO_IN ? POLLIN : 0) | 63*73fd282eSStefan Hajnoczi (pfd_events & G_IO_OUT ? POLLOUT : 0) | 64*73fd282eSStefan Hajnoczi (pfd_events & G_IO_HUP ? POLLHUP : 0) | 65*73fd282eSStefan Hajnoczi (pfd_events & G_IO_ERR ? POLLERR : 0); 66*73fd282eSStefan Hajnoczi } 67*73fd282eSStefan Hajnoczi 68*73fd282eSStefan Hajnoczi static inline int pfd_events_from_poll(int poll_events) 69*73fd282eSStefan Hajnoczi { 70*73fd282eSStefan Hajnoczi return (poll_events & POLLIN ? G_IO_IN : 0) | 71*73fd282eSStefan Hajnoczi (poll_events & POLLOUT ? G_IO_OUT : 0) | 72*73fd282eSStefan Hajnoczi (poll_events & POLLHUP ? G_IO_HUP : 0) | 73*73fd282eSStefan Hajnoczi (poll_events & POLLERR ? G_IO_ERR : 0); 74*73fd282eSStefan Hajnoczi } 75*73fd282eSStefan Hajnoczi 76*73fd282eSStefan Hajnoczi /* 77*73fd282eSStefan Hajnoczi * Returns an sqe for submitting a request. Only be called within 78*73fd282eSStefan Hajnoczi * fdmon_io_uring_wait(). 79*73fd282eSStefan Hajnoczi */ 80*73fd282eSStefan Hajnoczi static struct io_uring_sqe *get_sqe(AioContext *ctx) 81*73fd282eSStefan Hajnoczi { 82*73fd282eSStefan Hajnoczi struct io_uring *ring = &ctx->fdmon_io_uring; 83*73fd282eSStefan Hajnoczi struct io_uring_sqe *sqe = io_uring_get_sqe(ring); 84*73fd282eSStefan Hajnoczi int ret; 85*73fd282eSStefan Hajnoczi 86*73fd282eSStefan Hajnoczi if (likely(sqe)) { 87*73fd282eSStefan Hajnoczi return sqe; 88*73fd282eSStefan Hajnoczi } 89*73fd282eSStefan Hajnoczi 90*73fd282eSStefan Hajnoczi /* No free sqes left, submit pending sqes first */ 91*73fd282eSStefan Hajnoczi ret = io_uring_submit(ring); 92*73fd282eSStefan Hajnoczi assert(ret > 1); 93*73fd282eSStefan Hajnoczi sqe = io_uring_get_sqe(ring); 94*73fd282eSStefan Hajnoczi assert(sqe); 95*73fd282eSStefan Hajnoczi return sqe; 96*73fd282eSStefan Hajnoczi } 97*73fd282eSStefan Hajnoczi 98*73fd282eSStefan Hajnoczi /* Atomically enqueue an AioHandler for sq ring submission */ 99*73fd282eSStefan Hajnoczi static void enqueue(AioHandlerSList *head, AioHandler *node, unsigned flags) 100*73fd282eSStefan Hajnoczi { 101*73fd282eSStefan Hajnoczi unsigned old_flags; 102*73fd282eSStefan Hajnoczi 103*73fd282eSStefan Hajnoczi old_flags = atomic_fetch_or(&node->flags, FDMON_IO_URING_PENDING | flags); 104*73fd282eSStefan Hajnoczi if (!(old_flags & FDMON_IO_URING_PENDING)) { 105*73fd282eSStefan Hajnoczi QSLIST_INSERT_HEAD_ATOMIC(head, node, node_submitted); 106*73fd282eSStefan Hajnoczi } 107*73fd282eSStefan Hajnoczi } 108*73fd282eSStefan Hajnoczi 109*73fd282eSStefan Hajnoczi /* Dequeue an AioHandler for sq ring submission. Called by fill_sq_ring(). */ 110*73fd282eSStefan Hajnoczi static AioHandler *dequeue(AioHandlerSList *head, unsigned *flags) 111*73fd282eSStefan Hajnoczi { 112*73fd282eSStefan Hajnoczi AioHandler *node = QSLIST_FIRST(head); 113*73fd282eSStefan Hajnoczi 114*73fd282eSStefan Hajnoczi if (!node) { 115*73fd282eSStefan Hajnoczi return NULL; 116*73fd282eSStefan Hajnoczi } 117*73fd282eSStefan Hajnoczi 118*73fd282eSStefan Hajnoczi /* Doesn't need to be atomic since fill_sq_ring() moves the list */ 119*73fd282eSStefan Hajnoczi QSLIST_REMOVE_HEAD(head, node_submitted); 120*73fd282eSStefan Hajnoczi 121*73fd282eSStefan Hajnoczi /* 122*73fd282eSStefan Hajnoczi * Don't clear FDMON_IO_URING_REMOVE. It's sticky so it can serve two 123*73fd282eSStefan Hajnoczi * purposes: telling fill_sq_ring() to submit IORING_OP_POLL_REMOVE and 124*73fd282eSStefan Hajnoczi * telling process_cqe() to delete the AioHandler when its 125*73fd282eSStefan Hajnoczi * IORING_OP_POLL_ADD completes. 126*73fd282eSStefan Hajnoczi */ 127*73fd282eSStefan Hajnoczi *flags = atomic_fetch_and(&node->flags, ~(FDMON_IO_URING_PENDING | 128*73fd282eSStefan Hajnoczi FDMON_IO_URING_ADD)); 129*73fd282eSStefan Hajnoczi return node; 130*73fd282eSStefan Hajnoczi } 131*73fd282eSStefan Hajnoczi 132*73fd282eSStefan Hajnoczi static void fdmon_io_uring_update(AioContext *ctx, 133*73fd282eSStefan Hajnoczi AioHandler *old_node, 134*73fd282eSStefan Hajnoczi AioHandler *new_node) 135*73fd282eSStefan Hajnoczi { 136*73fd282eSStefan Hajnoczi if (new_node) { 137*73fd282eSStefan Hajnoczi enqueue(&ctx->submit_list, new_node, FDMON_IO_URING_ADD); 138*73fd282eSStefan Hajnoczi } 139*73fd282eSStefan Hajnoczi 140*73fd282eSStefan Hajnoczi if (old_node) { 141*73fd282eSStefan Hajnoczi /* 142*73fd282eSStefan Hajnoczi * Deletion is tricky because IORING_OP_POLL_ADD and 143*73fd282eSStefan Hajnoczi * IORING_OP_POLL_REMOVE are async. We need to wait for the original 144*73fd282eSStefan Hajnoczi * IORING_OP_POLL_ADD to complete before this handler can be freed 145*73fd282eSStefan Hajnoczi * safely. 146*73fd282eSStefan Hajnoczi * 147*73fd282eSStefan Hajnoczi * It's possible that the file descriptor becomes ready and the 148*73fd282eSStefan Hajnoczi * IORING_OP_POLL_ADD cqe is enqueued before IORING_OP_POLL_REMOVE is 149*73fd282eSStefan Hajnoczi * submitted, too. 150*73fd282eSStefan Hajnoczi * 151*73fd282eSStefan Hajnoczi * Mark this handler deleted right now but don't place it on 152*73fd282eSStefan Hajnoczi * ctx->deleted_aio_handlers yet. Instead, manually fudge the list 153*73fd282eSStefan Hajnoczi * entry to make QLIST_IS_INSERTED() think this handler has been 154*73fd282eSStefan Hajnoczi * inserted and other code recognizes this AioHandler as deleted. 155*73fd282eSStefan Hajnoczi * 156*73fd282eSStefan Hajnoczi * Once the original IORING_OP_POLL_ADD completes we enqueue the 157*73fd282eSStefan Hajnoczi * handler on the real ctx->deleted_aio_handlers list to be freed. 158*73fd282eSStefan Hajnoczi */ 159*73fd282eSStefan Hajnoczi assert(!QLIST_IS_INSERTED(old_node, node_deleted)); 160*73fd282eSStefan Hajnoczi old_node->node_deleted.le_prev = &old_node->node_deleted.le_next; 161*73fd282eSStefan Hajnoczi 162*73fd282eSStefan Hajnoczi enqueue(&ctx->submit_list, old_node, FDMON_IO_URING_REMOVE); 163*73fd282eSStefan Hajnoczi } 164*73fd282eSStefan Hajnoczi } 165*73fd282eSStefan Hajnoczi 166*73fd282eSStefan Hajnoczi static void add_poll_add_sqe(AioContext *ctx, AioHandler *node) 167*73fd282eSStefan Hajnoczi { 168*73fd282eSStefan Hajnoczi struct io_uring_sqe *sqe = get_sqe(ctx); 169*73fd282eSStefan Hajnoczi int events = poll_events_from_pfd(node->pfd.events); 170*73fd282eSStefan Hajnoczi 171*73fd282eSStefan Hajnoczi io_uring_prep_poll_add(sqe, node->pfd.fd, events); 172*73fd282eSStefan Hajnoczi io_uring_sqe_set_data(sqe, node); 173*73fd282eSStefan Hajnoczi } 174*73fd282eSStefan Hajnoczi 175*73fd282eSStefan Hajnoczi static void add_poll_remove_sqe(AioContext *ctx, AioHandler *node) 176*73fd282eSStefan Hajnoczi { 177*73fd282eSStefan Hajnoczi struct io_uring_sqe *sqe = get_sqe(ctx); 178*73fd282eSStefan Hajnoczi 179*73fd282eSStefan Hajnoczi io_uring_prep_poll_remove(sqe, node); 180*73fd282eSStefan Hajnoczi } 181*73fd282eSStefan Hajnoczi 182*73fd282eSStefan Hajnoczi /* Add a timeout that self-cancels when another cqe becomes ready */ 183*73fd282eSStefan Hajnoczi static void add_timeout_sqe(AioContext *ctx, int64_t ns) 184*73fd282eSStefan Hajnoczi { 185*73fd282eSStefan Hajnoczi struct io_uring_sqe *sqe; 186*73fd282eSStefan Hajnoczi struct __kernel_timespec ts = { 187*73fd282eSStefan Hajnoczi .tv_sec = ns / NANOSECONDS_PER_SECOND, 188*73fd282eSStefan Hajnoczi .tv_nsec = ns % NANOSECONDS_PER_SECOND, 189*73fd282eSStefan Hajnoczi }; 190*73fd282eSStefan Hajnoczi 191*73fd282eSStefan Hajnoczi sqe = get_sqe(ctx); 192*73fd282eSStefan Hajnoczi io_uring_prep_timeout(sqe, &ts, 1, 0); 193*73fd282eSStefan Hajnoczi } 194*73fd282eSStefan Hajnoczi 195*73fd282eSStefan Hajnoczi /* Add sqes from ctx->submit_list for submission */ 196*73fd282eSStefan Hajnoczi static void fill_sq_ring(AioContext *ctx) 197*73fd282eSStefan Hajnoczi { 198*73fd282eSStefan Hajnoczi AioHandlerSList submit_list; 199*73fd282eSStefan Hajnoczi AioHandler *node; 200*73fd282eSStefan Hajnoczi unsigned flags; 201*73fd282eSStefan Hajnoczi 202*73fd282eSStefan Hajnoczi QSLIST_MOVE_ATOMIC(&submit_list, &ctx->submit_list); 203*73fd282eSStefan Hajnoczi 204*73fd282eSStefan Hajnoczi while ((node = dequeue(&submit_list, &flags))) { 205*73fd282eSStefan Hajnoczi /* Order matters, just in case both flags were set */ 206*73fd282eSStefan Hajnoczi if (flags & FDMON_IO_URING_ADD) { 207*73fd282eSStefan Hajnoczi add_poll_add_sqe(ctx, node); 208*73fd282eSStefan Hajnoczi } 209*73fd282eSStefan Hajnoczi if (flags & FDMON_IO_URING_REMOVE) { 210*73fd282eSStefan Hajnoczi add_poll_remove_sqe(ctx, node); 211*73fd282eSStefan Hajnoczi } 212*73fd282eSStefan Hajnoczi } 213*73fd282eSStefan Hajnoczi } 214*73fd282eSStefan Hajnoczi 215*73fd282eSStefan Hajnoczi /* Returns true if a handler became ready */ 216*73fd282eSStefan Hajnoczi static bool process_cqe(AioContext *ctx, 217*73fd282eSStefan Hajnoczi AioHandlerList *ready_list, 218*73fd282eSStefan Hajnoczi struct io_uring_cqe *cqe) 219*73fd282eSStefan Hajnoczi { 220*73fd282eSStefan Hajnoczi AioHandler *node = io_uring_cqe_get_data(cqe); 221*73fd282eSStefan Hajnoczi unsigned flags; 222*73fd282eSStefan Hajnoczi 223*73fd282eSStefan Hajnoczi /* poll_timeout and poll_remove have a zero user_data field */ 224*73fd282eSStefan Hajnoczi if (!node) { 225*73fd282eSStefan Hajnoczi return false; 226*73fd282eSStefan Hajnoczi } 227*73fd282eSStefan Hajnoczi 228*73fd282eSStefan Hajnoczi /* 229*73fd282eSStefan Hajnoczi * Deletion can only happen when IORING_OP_POLL_ADD completes. If we race 230*73fd282eSStefan Hajnoczi * with enqueue() here then we can safely clear the FDMON_IO_URING_REMOVE 231*73fd282eSStefan Hajnoczi * bit before IORING_OP_POLL_REMOVE is submitted. 232*73fd282eSStefan Hajnoczi */ 233*73fd282eSStefan Hajnoczi flags = atomic_fetch_and(&node->flags, ~FDMON_IO_URING_REMOVE); 234*73fd282eSStefan Hajnoczi if (flags & FDMON_IO_URING_REMOVE) { 235*73fd282eSStefan Hajnoczi QLIST_INSERT_HEAD_RCU(&ctx->deleted_aio_handlers, node, node_deleted); 236*73fd282eSStefan Hajnoczi return false; 237*73fd282eSStefan Hajnoczi } 238*73fd282eSStefan Hajnoczi 239*73fd282eSStefan Hajnoczi aio_add_ready_handler(ready_list, node, pfd_events_from_poll(cqe->res)); 240*73fd282eSStefan Hajnoczi 241*73fd282eSStefan Hajnoczi /* IORING_OP_POLL_ADD is one-shot so we must re-arm it */ 242*73fd282eSStefan Hajnoczi add_poll_add_sqe(ctx, node); 243*73fd282eSStefan Hajnoczi return true; 244*73fd282eSStefan Hajnoczi } 245*73fd282eSStefan Hajnoczi 246*73fd282eSStefan Hajnoczi static int process_cq_ring(AioContext *ctx, AioHandlerList *ready_list) 247*73fd282eSStefan Hajnoczi { 248*73fd282eSStefan Hajnoczi struct io_uring *ring = &ctx->fdmon_io_uring; 249*73fd282eSStefan Hajnoczi struct io_uring_cqe *cqe; 250*73fd282eSStefan Hajnoczi unsigned num_cqes = 0; 251*73fd282eSStefan Hajnoczi unsigned num_ready = 0; 252*73fd282eSStefan Hajnoczi unsigned head; 253*73fd282eSStefan Hajnoczi 254*73fd282eSStefan Hajnoczi io_uring_for_each_cqe(ring, head, cqe) { 255*73fd282eSStefan Hajnoczi if (process_cqe(ctx, ready_list, cqe)) { 256*73fd282eSStefan Hajnoczi num_ready++; 257*73fd282eSStefan Hajnoczi } 258*73fd282eSStefan Hajnoczi 259*73fd282eSStefan Hajnoczi num_cqes++; 260*73fd282eSStefan Hajnoczi } 261*73fd282eSStefan Hajnoczi 262*73fd282eSStefan Hajnoczi io_uring_cq_advance(ring, num_cqes); 263*73fd282eSStefan Hajnoczi return num_ready; 264*73fd282eSStefan Hajnoczi } 265*73fd282eSStefan Hajnoczi 266*73fd282eSStefan Hajnoczi static int fdmon_io_uring_wait(AioContext *ctx, AioHandlerList *ready_list, 267*73fd282eSStefan Hajnoczi int64_t timeout) 268*73fd282eSStefan Hajnoczi { 269*73fd282eSStefan Hajnoczi unsigned wait_nr = 1; /* block until at least one cqe is ready */ 270*73fd282eSStefan Hajnoczi int ret; 271*73fd282eSStefan Hajnoczi 272*73fd282eSStefan Hajnoczi /* Fall back while external clients are disabled */ 273*73fd282eSStefan Hajnoczi if (atomic_read(&ctx->external_disable_cnt)) { 274*73fd282eSStefan Hajnoczi return fdmon_poll_ops.wait(ctx, ready_list, timeout); 275*73fd282eSStefan Hajnoczi } 276*73fd282eSStefan Hajnoczi 277*73fd282eSStefan Hajnoczi if (timeout == 0) { 278*73fd282eSStefan Hajnoczi wait_nr = 0; /* non-blocking */ 279*73fd282eSStefan Hajnoczi } else if (timeout > 0) { 280*73fd282eSStefan Hajnoczi add_timeout_sqe(ctx, timeout); 281*73fd282eSStefan Hajnoczi } 282*73fd282eSStefan Hajnoczi 283*73fd282eSStefan Hajnoczi fill_sq_ring(ctx); 284*73fd282eSStefan Hajnoczi 285*73fd282eSStefan Hajnoczi ret = io_uring_submit_and_wait(&ctx->fdmon_io_uring, wait_nr); 286*73fd282eSStefan Hajnoczi assert(ret >= 0); 287*73fd282eSStefan Hajnoczi 288*73fd282eSStefan Hajnoczi return process_cq_ring(ctx, ready_list); 289*73fd282eSStefan Hajnoczi } 290*73fd282eSStefan Hajnoczi 291*73fd282eSStefan Hajnoczi static const FDMonOps fdmon_io_uring_ops = { 292*73fd282eSStefan Hajnoczi .update = fdmon_io_uring_update, 293*73fd282eSStefan Hajnoczi .wait = fdmon_io_uring_wait, 294*73fd282eSStefan Hajnoczi }; 295*73fd282eSStefan Hajnoczi 296*73fd282eSStefan Hajnoczi bool fdmon_io_uring_setup(AioContext *ctx) 297*73fd282eSStefan Hajnoczi { 298*73fd282eSStefan Hajnoczi int ret; 299*73fd282eSStefan Hajnoczi 300*73fd282eSStefan Hajnoczi ret = io_uring_queue_init(FDMON_IO_URING_ENTRIES, &ctx->fdmon_io_uring, 0); 301*73fd282eSStefan Hajnoczi if (ret != 0) { 302*73fd282eSStefan Hajnoczi return false; 303*73fd282eSStefan Hajnoczi } 304*73fd282eSStefan Hajnoczi 305*73fd282eSStefan Hajnoczi QSLIST_INIT(&ctx->submit_list); 306*73fd282eSStefan Hajnoczi ctx->fdmon_ops = &fdmon_io_uring_ops; 307*73fd282eSStefan Hajnoczi return true; 308*73fd282eSStefan Hajnoczi } 309*73fd282eSStefan Hajnoczi 310*73fd282eSStefan Hajnoczi void fdmon_io_uring_destroy(AioContext *ctx) 311*73fd282eSStefan Hajnoczi { 312*73fd282eSStefan Hajnoczi if (ctx->fdmon_ops == &fdmon_io_uring_ops) { 313*73fd282eSStefan Hajnoczi AioHandler *node; 314*73fd282eSStefan Hajnoczi 315*73fd282eSStefan Hajnoczi io_uring_queue_exit(&ctx->fdmon_io_uring); 316*73fd282eSStefan Hajnoczi 317*73fd282eSStefan Hajnoczi /* No need to submit these anymore, just free them. */ 318*73fd282eSStefan Hajnoczi while ((node = QSLIST_FIRST_RCU(&ctx->submit_list))) { 319*73fd282eSStefan Hajnoczi QSLIST_REMOVE_HEAD_RCU(&ctx->submit_list, node_submitted); 320*73fd282eSStefan Hajnoczi QLIST_REMOVE(node, node); 321*73fd282eSStefan Hajnoczi g_free(node); 322*73fd282eSStefan Hajnoczi } 323*73fd282eSStefan Hajnoczi 324*73fd282eSStefan Hajnoczi ctx->fdmon_ops = &fdmon_poll_ops; 325*73fd282eSStefan Hajnoczi } 326*73fd282eSStefan Hajnoczi } 327