Line data Source code
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 0 : aio_mgr_get_aio(struct spdk_aio_mgr *mgr, fsdev_aio_done_cb clb, void *ctx)
34 : {
35 0 : struct spdk_aio_mgr_io *aio = TAILQ_FIRST(&mgr->aios.pool);
36 :
37 0 : if (aio) {
38 0 : aio->mgr = mgr;
39 0 : aio->clb = clb;
40 0 : aio->ctx = ctx;
41 0 : aio->err = 0;
42 0 : aio->data_size = 0;
43 0 : TAILQ_REMOVE(&mgr->aios.pool, aio, link);
44 : }
45 :
46 0 : return aio;
47 : }
48 :
49 : static inline void
50 0 : aio_mgr_put_aio(struct spdk_aio_mgr *mgr, struct spdk_aio_mgr_io *aio)
51 : {
52 0 : TAILQ_INSERT_TAIL(&aio->mgr->aios.pool, aio, link);
53 0 : }
54 :
55 : static void
56 0 : spdk_aio_mgr_io_cpl_cb(io_context_t ctx, struct iocb *iocb, long res, long res2)
57 : {
58 0 : struct spdk_aio_mgr_io *aio = SPDK_CONTAINEROF(iocb, struct spdk_aio_mgr_io, io);
59 :
60 0 : TAILQ_REMOVE(&aio->mgr->in_flight, aio, link);
61 :
62 0 : aio->clb(aio->ctx, res, -res2);
63 :
64 0 : aio_mgr_put_aio(aio->mgr, aio);
65 0 : }
66 :
67 : static struct spdk_aio_mgr_io *
68 0 : 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 0 : struct iocb *ios[1];
74 :
75 0 : 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 0 : aio = aio_mgr_get_aio(mgr, clb, ctx);
79 0 : if (!aio) {
80 0 : SPDK_ERRLOG("Cannot get aio\n");
81 0 : clb(ctx, 0, EFAULT);
82 0 : return NULL;
83 : }
84 :
85 0 : if (read) {
86 0 : io_prep_preadv(&aio->io, fd, iovs, iovcnt, offs);
87 : } else {
88 0 : io_prep_pwritev(&aio->io, fd, iovs, iovcnt, offs);
89 : }
90 0 : io_set_callback(&aio->io, spdk_aio_mgr_io_cpl_cb);
91 :
92 :
93 0 : ios[0] = &aio->io;
94 0 : res = io_submit(mgr->io_ctx, 1, ios);
95 0 : SPDK_DEBUGLOG(spdk_aio_mgr_io, "%s: aio=%p submitted with res=%d\n", read ? "read" : "write", aio,
96 : res);
97 0 : if (res) {
98 0 : TAILQ_INSERT_TAIL(&aio->mgr->in_flight, aio, link);
99 0 : return aio;
100 : } else {
101 0 : aio->clb(aio->ctx, 0, aio->err);
102 0 : aio_mgr_put_aio(mgr, aio);
103 0 : return NULL;
104 : }
105 :
106 : }
107 :
108 : struct spdk_aio_mgr *
109 0 : spdk_aio_mgr_create(uint32_t max_aios)
110 : {
111 : struct spdk_aio_mgr *mgr;
112 : int res;
113 : uint32_t i;
114 :
115 0 : mgr = calloc(1, sizeof(*mgr));
116 0 : if (!mgr) {
117 0 : SPDK_ERRLOG("cannot alloc mgr of %zu bytes\n", sizeof(*mgr));
118 0 : return NULL;
119 : }
120 :
121 0 : res = io_queue_init(max_aios, &mgr->io_ctx);
122 0 : if (res) {
123 0 : SPDK_ERRLOG("io_setup(%" PRIu32 ") failed with %d\n", max_aios, res);
124 0 : free(mgr);
125 0 : return NULL;
126 : }
127 :
128 0 : mgr->aios.arr = calloc(max_aios, sizeof(mgr->aios.arr[0]));
129 0 : if (!mgr->aios.arr) {
130 0 : SPDK_ERRLOG("cannot alloc aios pool of %" PRIu32 "\n", max_aios);
131 0 : io_queue_release(mgr->io_ctx);
132 0 : free(mgr);
133 0 : return NULL;
134 : }
135 :
136 0 : TAILQ_INIT(&mgr->in_flight);
137 0 : TAILQ_INIT(&mgr->aios.pool);
138 :
139 0 : for (i = 0; i < max_aios; i++) {
140 0 : TAILQ_INSERT_TAIL(&mgr->aios.pool, &mgr->aios.arr[i], link);
141 : }
142 :
143 0 : return mgr;
144 : }
145 :
146 : struct spdk_aio_mgr_io *
147 0 : 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 0 : return spdk_aio_mgr_submit_io(mgr, clb, ctx, fd, offs, size, iovs, iovcnt, true);
151 : }
152 :
153 : struct spdk_aio_mgr_io *
154 0 : 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 0 : return spdk_aio_mgr_submit_io(mgr, clb, ctx, fd, offs, size, (struct iovec *)iovs, iovcnt, false);
158 : }
159 :
160 : void
161 0 : spdk_aio_mgr_cancel(struct spdk_aio_mgr *mgr, struct spdk_aio_mgr_io *aio)
162 : {
163 : int res;
164 0 : struct io_event result;
165 :
166 0 : assert(mgr == aio->mgr);
167 :
168 0 : res = io_cancel(mgr->io_ctx, &aio->io, &result);
169 0 : if (res) {
170 0 : SPDK_DEBUGLOG(spdk_aio_mgr_io, "aio=%p cancelled\n", aio);
171 0 : spdk_aio_mgr_io_cpl_cb(mgr->io_ctx, &aio->io, ECANCELED, 0);
172 : } else {
173 0 : SPDK_WARNLOG("aio=%p cancellation failed with err=%d\n", aio, res);
174 : }
175 0 : }
176 :
177 : void
178 0 : spdk_aio_mgr_poll(struct spdk_aio_mgr *mgr)
179 : {
180 : int res;
181 :
182 0 : res = io_queue_run(mgr->io_ctx);
183 0 : if (res) {
184 0 : SPDK_WARNLOG("polling failed with err=%d\n", res);
185 : }
186 0 : }
187 :
188 : void
189 0 : spdk_aio_mgr_delete(struct spdk_aio_mgr *mgr)
190 : {
191 0 : assert(TAILQ_EMPTY(&mgr->in_flight));
192 0 : free(mgr->aios.arr);
193 0 : io_queue_release(mgr->io_ctx);
194 0 : free(mgr);
195 0 : }
196 :
197 0 : SPDK_LOG_REGISTER_COMPONENT(spdk_aio_mgr_io)
|