4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "blockdev_aio.h"
42 #include <sys/ioctl.h>
44 #include "spdk/bdev.h"
45 #include "spdk/conf.h"
48 #include "spdk/io_channel.h"
50 #include "spdk_internal/log.h"
52 static int blockdev_aio_initialize(void);
53 static void aio_free_disk(struct file_disk
*fdisk
);
56 blockdev_aio_get_ctx_size(void)
58 return sizeof(struct blockdev_aio_task
);
61 SPDK_BDEV_MODULE_REGISTER(blockdev_aio_initialize
, NULL
, NULL
, blockdev_aio_get_ctx_size
)
64 blockdev_aio_open(struct file_disk
*disk
)
68 fd
= open(disk
->file
, O_RDWR
| O_DIRECT
);
81 blockdev_aio_close(struct file_disk
*disk
)
101 blockdev_aio_readv(struct file_disk
*fdisk
, struct spdk_io_channel
*ch
,
102 struct blockdev_aio_task
*aio_task
,
103 struct iovec
*iov
, int iovcnt
, uint64_t nbytes
, uint64_t offset
)
105 struct iocb
*iocb
= &aio_task
->iocb
;
106 struct blockdev_aio_io_channel
*aio_ch
= spdk_io_channel_get_ctx(ch
);
109 io_prep_preadv(iocb
, fdisk
->fd
, iov
, iovcnt
, offset
);
110 iocb
->data
= aio_task
;
111 aio_task
->len
= nbytes
;
113 SPDK_TRACELOG(SPDK_TRACE_AIO
, "read %d iovs size %lu to off: %#lx\n",
114 iovcnt
, nbytes
, offset
);
116 rc
= io_submit(aio_ch
->io_ctx
, 1, &iocb
);
118 spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task
), SPDK_BDEV_IO_STATUS_FAILED
);
119 SPDK_ERRLOG("%s: io_submit returned %d\n", __func__
, rc
);
127 blockdev_aio_writev(struct file_disk
*fdisk
, struct spdk_io_channel
*ch
,
128 struct blockdev_aio_task
*aio_task
,
129 struct iovec
*iov
, int iovcnt
, size_t len
, uint64_t offset
)
131 struct iocb
*iocb
= &aio_task
->iocb
;
132 struct blockdev_aio_io_channel
*aio_ch
= spdk_io_channel_get_ctx(ch
);
135 io_prep_pwritev(iocb
, fdisk
->fd
, iov
, iovcnt
, offset
);
136 iocb
->data
= aio_task
;
139 SPDK_TRACELOG(SPDK_TRACE_AIO
, "write %d iovs size %lu from off: %#lx\n",
140 iovcnt
, len
, offset
);
142 rc
= io_submit(aio_ch
->io_ctx
, 1, &iocb
);
144 spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task
), SPDK_BDEV_IO_STATUS_FAILED
);
145 SPDK_ERRLOG("%s: io_submit returned %d\n", __func__
, rc
);
153 blockdev_aio_flush(struct file_disk
*fdisk
, struct blockdev_aio_task
*aio_task
,
154 uint64_t offset
, uint64_t nbytes
)
156 int rc
= fsync(fdisk
->fd
);
158 spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task
),
159 rc
== 0 ? SPDK_BDEV_IO_STATUS_SUCCESS
: SPDK_BDEV_IO_STATUS_FAILED
);
163 blockdev_aio_destruct(void *ctx
)
165 struct file_disk
*fdisk
= ctx
;
168 rc
= blockdev_aio_close(fdisk
);
170 SPDK_ERRLOG("blockdev_aio_close() failed\n");
172 aio_free_disk(fdisk
);
177 blockdev_aio_initialize_io_channel(struct blockdev_aio_io_channel
*ch
)
179 ch
->queue_depth
= 128;
181 if (io_setup(ch
->queue_depth
, &ch
->io_ctx
) < 0) {
182 SPDK_ERRLOG("async I/O context setup failure\n");
186 ch
->events
= calloc(sizeof(struct io_event
), ch
->queue_depth
);
188 io_destroy(ch
->io_ctx
);
196 blockdev_aio_poll(void *arg
)
198 struct blockdev_aio_io_channel
*ch
= arg
;
200 enum spdk_bdev_io_status status
;
201 struct blockdev_aio_task
*aio_task
;
202 struct timespec timeout
;
207 nr
= io_getevents(ch
->io_ctx
, 1, ch
->queue_depth
,
208 ch
->events
, &timeout
);
211 SPDK_ERRLOG("%s: io_getevents returned %d\n", __func__
, nr
);
215 for (i
= 0; i
< nr
; i
++) {
216 aio_task
= ch
->events
[i
].data
;
217 if (ch
->events
[i
].res
!= aio_task
->len
) {
218 status
= SPDK_BDEV_IO_STATUS_FAILED
;
220 status
= SPDK_BDEV_IO_STATUS_SUCCESS
;
223 spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task
), status
);
228 blockdev_aio_reset(struct file_disk
*fdisk
, struct blockdev_aio_task
*aio_task
)
230 spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task
), SPDK_BDEV_IO_STATUS_SUCCESS
);
233 static void blockdev_aio_get_rbuf_cb(struct spdk_bdev_io
*bdev_io
)
235 blockdev_aio_readv((struct file_disk
*)bdev_io
->ctx
,
237 (struct blockdev_aio_task
*)bdev_io
->driver_ctx
,
238 bdev_io
->u
.read
.iovs
,
239 bdev_io
->u
.read
.iovcnt
,
241 bdev_io
->u
.read
.offset
);
244 static int _blockdev_aio_submit_request(struct spdk_bdev_io
*bdev_io
)
246 switch (bdev_io
->type
) {
247 case SPDK_BDEV_IO_TYPE_READ
:
248 spdk_bdev_io_get_rbuf(bdev_io
, blockdev_aio_get_rbuf_cb
);
251 case SPDK_BDEV_IO_TYPE_WRITE
:
252 blockdev_aio_writev((struct file_disk
*)bdev_io
->ctx
,
254 (struct blockdev_aio_task
*)bdev_io
->driver_ctx
,
255 bdev_io
->u
.write
.iovs
,
256 bdev_io
->u
.write
.iovcnt
,
257 bdev_io
->u
.write
.len
,
258 bdev_io
->u
.write
.offset
);
260 case SPDK_BDEV_IO_TYPE_FLUSH
:
261 blockdev_aio_flush((struct file_disk
*)bdev_io
->ctx
,
262 (struct blockdev_aio_task
*)bdev_io
->driver_ctx
,
263 bdev_io
->u
.flush
.offset
,
264 bdev_io
->u
.flush
.length
);
267 case SPDK_BDEV_IO_TYPE_RESET
:
268 blockdev_aio_reset((struct file_disk
*)bdev_io
->ctx
,
269 (struct blockdev_aio_task
*)bdev_io
->driver_ctx
);
276 static void blockdev_aio_submit_request(struct spdk_bdev_io
*bdev_io
)
278 if (_blockdev_aio_submit_request(bdev_io
) < 0) {
279 spdk_bdev_io_complete(bdev_io
, SPDK_BDEV_IO_STATUS_FAILED
);
284 blockdev_aio_io_type_supported(void *ctx
, enum spdk_bdev_io_type io_type
)
287 case SPDK_BDEV_IO_TYPE_READ
:
288 case SPDK_BDEV_IO_TYPE_WRITE
:
289 case SPDK_BDEV_IO_TYPE_FLUSH
:
290 case SPDK_BDEV_IO_TYPE_RESET
:
299 blockdev_aio_create_cb(void *io_device
, uint32_t priority
, void *ctx_buf
, void *unique_ctx
)
301 struct blockdev_aio_io_channel
*ch
= ctx_buf
;
303 if (blockdev_aio_initialize_io_channel(ch
) != 0) {
307 spdk_poller_register(&ch
->poller
, blockdev_aio_poll
, ch
,
308 spdk_env_get_current_core(), 0);
313 blockdev_aio_destroy_cb(void *io_device
, void *ctx_buf
)
315 struct blockdev_aio_io_channel
*io_channel
= ctx_buf
;
317 io_destroy(io_channel
->io_ctx
);
318 free(io_channel
->events
);
319 spdk_poller_unregister(&io_channel
->poller
, NULL
);
322 static struct spdk_io_channel
*
323 blockdev_aio_get_io_channel(void *ctx
, uint32_t priority
)
325 struct file_disk
*fdisk
= ctx
;
327 return spdk_get_io_channel(&fdisk
->fd
, priority
, false, NULL
);
330 static const struct spdk_bdev_fn_table aio_fn_table
= {
331 .destruct
= blockdev_aio_destruct
,
332 .submit_request
= blockdev_aio_submit_request
,
333 .io_type_supported
= blockdev_aio_io_type_supported
,
334 .get_io_channel
= blockdev_aio_get_io_channel
,
337 static void aio_free_disk(struct file_disk
*fdisk
)
345 create_aio_disk(const char *name
, const char *fname
)
347 struct file_disk
*fdisk
;
349 fdisk
= calloc(sizeof(*fdisk
), 1);
351 SPDK_ERRLOG("Unable to allocate enough memory for aio backend\n");
356 if (blockdev_aio_open(fdisk
)) {
357 SPDK_ERRLOG("Unable to open file %s. fd: %d errno: %d\n", fname
, fdisk
->fd
, errno
);
361 fdisk
->size
= spdk_fd_get_size(fdisk
->fd
);
363 TAILQ_INIT(&fdisk
->sync_completion_list
);
364 snprintf(fdisk
->disk
.name
, SPDK_BDEV_MAX_NAME_LENGTH
, "%s", name
);
365 snprintf(fdisk
->disk
.product_name
, SPDK_BDEV_MAX_PRODUCT_NAME_LENGTH
, "AIO disk");
367 fdisk
->disk
.need_aligned_buffer
= 1;
368 fdisk
->disk
.write_cache
= 1;
369 fdisk
->disk
.blocklen
= spdk_fd_get_blocklen(fdisk
->fd
);
370 fdisk
->disk
.blockcnt
= fdisk
->size
/ fdisk
->disk
.blocklen
;
371 fdisk
->disk
.ctxt
= fdisk
;
373 fdisk
->disk
.fn_table
= &aio_fn_table
;
375 spdk_io_device_register(&fdisk
->fd
, blockdev_aio_create_cb
, blockdev_aio_destroy_cb
,
376 sizeof(struct blockdev_aio_io_channel
));
377 spdk_bdev_register(&fdisk
->disk
);
381 blockdev_aio_close(fdisk
);
382 aio_free_disk(fdisk
);
386 static int blockdev_aio_initialize(void)
389 struct spdk_conf_section
*sp
;
390 struct spdk_bdev
*bdev
;
392 sp
= spdk_conf_find_section(NULL
, "AIO");
402 file
= spdk_conf_section_get_nmval(sp
, "AIO", i
, 0);
407 name
= spdk_conf_section_get_nmval(sp
, "AIO", i
, 1);
409 SPDK_ERRLOG("No name provided for AIO disk with file %s\n", file
);
414 bdev
= create_aio_disk(name
, file
);
416 SPDK_ERRLOG("Unable to create AIO bdev from file %s\n", file
);
427 SPDK_LOG_REGISTER_TRACE_FLAG("aio", SPDK_TRACE_AIO
)