1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 */ 4 #include "spdk/stdinc.h" 5 #include "spdk/util.h" 6 #include "spdk/log.h" 7 #include "aio_mgr.h" 8 #include <libaio.h> 9 10 #define MAX_EVENTS 1024 11 12 struct spdk_aio_mgr_io { 13 struct spdk_aio_mgr *mgr; 14 TAILQ_ENTRY(spdk_aio_mgr_io) link; 15 struct iocb io; 16 fsdev_aio_done_cb clb; 17 void *ctx; 18 uint32_t data_size; 19 int err; 20 }; 21 22 struct spdk_aio_mgr { 23 TAILQ_HEAD(, spdk_aio_mgr_io) in_flight; 24 io_context_t io_ctx; 25 struct { 26 struct spdk_aio_mgr_io *arr; 27 uint32_t size; 28 TAILQ_HEAD(, spdk_aio_mgr_io) pool; 29 } aios; 30 }; 31 32 static struct spdk_aio_mgr_io * 33 aio_mgr_get_aio(struct spdk_aio_mgr *mgr, fsdev_aio_done_cb clb, void *ctx) 34 { 35 struct spdk_aio_mgr_io *aio = TAILQ_FIRST(&mgr->aios.pool); 36 37 if (aio) { 38 aio->mgr = mgr; 39 aio->clb = clb; 40 aio->ctx = ctx; 41 aio->err = 0; 42 aio->data_size = 0; 43 TAILQ_REMOVE(&mgr->aios.pool, aio, link); 44 } 45 46 return aio; 47 } 48 49 static inline void 50 aio_mgr_put_aio(struct spdk_aio_mgr *mgr, struct spdk_aio_mgr_io *aio) 51 { 52 TAILQ_INSERT_TAIL(&aio->mgr->aios.pool, aio, link); 53 } 54 55 static void 56 spdk_aio_mgr_io_cpl_cb(io_context_t ctx, struct iocb *iocb, long res, long res2) 57 { 58 struct spdk_aio_mgr_io *aio = SPDK_CONTAINEROF(iocb, struct spdk_aio_mgr_io, io); 59 60 TAILQ_REMOVE(&aio->mgr->in_flight, aio, link); 61 62 aio->clb(aio->ctx, res, -res2); 63 64 aio_mgr_put_aio(aio->mgr, aio); 65 } 66 67 static struct spdk_aio_mgr_io * 68 spdk_aio_mgr_submit_io(struct spdk_aio_mgr *mgr, fsdev_aio_done_cb clb, void *ctx, int fd, 69 uint64_t offs, uint32_t size, struct iovec *iovs, uint32_t iovcnt, bool read) 70 { 71 struct spdk_aio_mgr_io *aio; 72 int res; 73 struct iocb *ios[1]; 74 75 SPDK_DEBUGLOG(spdk_aio_mgr_io, "%s: fd=%d offs=%" PRIu64 " size=%" PRIu32 " iovcnt=%" PRIu32 "\n", 76 read ? "read" : "write", fd, offs, size, iovcnt); 77 78 aio = aio_mgr_get_aio(mgr, clb, ctx); 79 if (!aio) { 80 SPDK_ERRLOG("Cannot get aio\n"); 81 clb(ctx, 0, EFAULT); 82 return NULL; 83 } 84 85 if (read) { 86 io_prep_preadv(&aio->io, fd, iovs, iovcnt, offs); 87 } else { 88 io_prep_pwritev(&aio->io, fd, iovs, iovcnt, offs); 89 } 90 io_set_callback(&aio->io, spdk_aio_mgr_io_cpl_cb); 91 92 93 ios[0] = &aio->io; 94 res = io_submit(mgr->io_ctx, 1, ios); 95 SPDK_DEBUGLOG(spdk_aio_mgr_io, "%s: aio=%p submitted with res=%d\n", read ? "read" : "write", aio, 96 res); 97 if (res) { 98 TAILQ_INSERT_TAIL(&aio->mgr->in_flight, aio, link); 99 return aio; 100 } else { 101 aio->clb(aio->ctx, 0, aio->err); 102 aio_mgr_put_aio(mgr, aio); 103 return NULL; 104 } 105 106 } 107 108 struct spdk_aio_mgr * 109 spdk_aio_mgr_create(uint32_t max_aios) 110 { 111 struct spdk_aio_mgr *mgr; 112 int res; 113 uint32_t i; 114 115 mgr = calloc(1, sizeof(*mgr)); 116 if (!mgr) { 117 SPDK_ERRLOG("cannot alloc mgr of %zu bytes\n", sizeof(*mgr)); 118 return NULL; 119 } 120 121 res = io_queue_init(max_aios, &mgr->io_ctx); 122 if (res) { 123 SPDK_ERRLOG("io_setup(%" PRIu32 ") failed with %d\n", max_aios, res); 124 free(mgr); 125 return NULL; 126 } 127 128 mgr->aios.arr = calloc(max_aios, sizeof(mgr->aios.arr[0])); 129 if (!mgr->aios.arr) { 130 SPDK_ERRLOG("cannot alloc aios pool of %" PRIu32 "\n", max_aios); 131 io_queue_release(mgr->io_ctx); 132 free(mgr); 133 return NULL; 134 } 135 136 TAILQ_INIT(&mgr->in_flight); 137 TAILQ_INIT(&mgr->aios.pool); 138 139 for (i = 0; i < max_aios; i++) { 140 TAILQ_INSERT_TAIL(&mgr->aios.pool, &mgr->aios.arr[i], link); 141 } 142 143 return mgr; 144 } 145 146 struct spdk_aio_mgr_io * 147 spdk_aio_mgr_read(struct spdk_aio_mgr *mgr, fsdev_aio_done_cb clb, void *ctx, 148 int fd, uint64_t offs, uint32_t size, struct iovec *iovs, uint32_t iovcnt) 149 { 150 return spdk_aio_mgr_submit_io(mgr, clb, ctx, fd, offs, size, iovs, iovcnt, true); 151 } 152 153 struct spdk_aio_mgr_io * 154 spdk_aio_mgr_write(struct spdk_aio_mgr *mgr, fsdev_aio_done_cb clb, void *ctx, 155 int fd, uint64_t offs, uint32_t size, const struct iovec *iovs, uint32_t iovcnt) 156 { 157 return spdk_aio_mgr_submit_io(mgr, clb, ctx, fd, offs, size, (struct iovec *)iovs, iovcnt, false); 158 } 159 160 void 161 spdk_aio_mgr_cancel(struct spdk_aio_mgr *mgr, struct spdk_aio_mgr_io *aio) 162 { 163 int res; 164 struct io_event result; 165 166 assert(mgr == aio->mgr); 167 168 res = io_cancel(mgr->io_ctx, &aio->io, &result); 169 if (res) { 170 SPDK_DEBUGLOG(spdk_aio_mgr_io, "aio=%p cancelled\n", aio); 171 spdk_aio_mgr_io_cpl_cb(mgr->io_ctx, &aio->io, ECANCELED, 0); 172 } else { 173 SPDK_WARNLOG("aio=%p cancellation failed with err=%d\n", aio, res); 174 } 175 } 176 177 void 178 spdk_aio_mgr_poll(struct spdk_aio_mgr *mgr) 179 { 180 int res; 181 182 res = io_queue_run(mgr->io_ctx); 183 if (res) { 184 SPDK_WARNLOG("polling failed with err=%d\n", res); 185 } 186 } 187 188 void 189 spdk_aio_mgr_delete(struct spdk_aio_mgr *mgr) 190 { 191 assert(TAILQ_EMPTY(&mgr->in_flight)); 192 free(mgr->aios.arr); 193 io_queue_release(mgr->io_ctx); 194 free(mgr); 195 } 196 197 SPDK_LOG_REGISTER_COMPONENT(spdk_aio_mgr_io) 198