]> git.proxmox.com Git - mirror_qemu.git/blame - block/blkio.c
stubs: add qemu_ram_block_from_host() and qemu_ram_get_fd()
[mirror_qemu.git] / block / blkio.c
CommitLineData
fd66dbd4
SH
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2/*
3 * libblkio BlockDriver
4 *
5 * Copyright Red Hat, Inc.
6 *
7 * Author:
8 * Stefan Hajnoczi <stefanha@redhat.com>
9 */
10
11#include "qemu/osdep.h"
12#include <blkio.h>
13#include "block/block_int.h"
14#include "qapi/error.h"
15#include "qapi/qmp/qdict.h"
16#include "qemu/module.h"
17
18/*
19 * Keep the QEMU BlockDriver names identical to the libblkio driver names.
20 * Using macros instead of typing out the string literals avoids typos.
21 */
22#define DRIVER_IO_URING "io_uring"
23#define DRIVER_NVME_IO_URING "nvme-io_uring"
24#define DRIVER_VIRTIO_BLK_VHOST_USER "virtio-blk-vhost-user"
25#define DRIVER_VIRTIO_BLK_VHOST_VDPA "virtio-blk-vhost-vdpa"
26
27/*
28 * Allocated bounce buffers are kept in a list sorted by buffer address.
29 */
30typedef struct BlkioBounceBuf {
31 QLIST_ENTRY(BlkioBounceBuf) next;
32
33 /* The bounce buffer */
34 struct iovec buf;
35} BlkioBounceBuf;
36
37typedef struct {
38 /*
39 * libblkio is not thread-safe so this lock protects ->blkio and
40 * ->blkioq.
41 */
42 QemuMutex blkio_lock;
43 struct blkio *blkio;
44 struct blkioq *blkioq; /* make this multi-queue in the future... */
45 int completion_fd;
46
47 /*
48 * Polling fetches the next completion into this field.
49 *
50 * No lock is necessary since only one thread calls aio_poll() and invokes
51 * fd and poll handlers.
52 */
53 struct blkio_completion poll_completion;
54
55 /*
56 * Protects ->bounce_pool, ->bounce_bufs, ->bounce_available.
57 *
58 * Lock ordering: ->bounce_lock before ->blkio_lock.
59 */
60 CoMutex bounce_lock;
61
62 /* Bounce buffer pool */
63 struct blkio_mem_region bounce_pool;
64
65 /* Sorted list of allocated bounce buffers */
66 QLIST_HEAD(, BlkioBounceBuf) bounce_bufs;
67
68 /* Queue for coroutines waiting for bounce buffer space */
69 CoQueue bounce_available;
70
71 /* The value of the "mem-region-alignment" property */
72 size_t mem_region_alignment;
73
74 /* Can we skip adding/deleting blkio_mem_regions? */
75 bool needs_mem_regions;
76} BDRVBlkioState;
77
78/* Called with s->bounce_lock held */
79static int blkio_resize_bounce_pool(BDRVBlkioState *s, int64_t bytes)
80{
81 /* There can be no allocated bounce buffers during resize */
82 assert(QLIST_EMPTY(&s->bounce_bufs));
83
84 /* Pad size to reduce frequency of resize calls */
85 bytes += 128 * 1024;
86
87 WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
88 int ret;
89
90 if (s->bounce_pool.addr) {
91 blkio_unmap_mem_region(s->blkio, &s->bounce_pool);
92 blkio_free_mem_region(s->blkio, &s->bounce_pool);
93 memset(&s->bounce_pool, 0, sizeof(s->bounce_pool));
94 }
95
96 /* Automatically freed when s->blkio is destroyed */
97 ret = blkio_alloc_mem_region(s->blkio, &s->bounce_pool, bytes);
98 if (ret < 0) {
99 return ret;
100 }
101
102 ret = blkio_map_mem_region(s->blkio, &s->bounce_pool);
103 if (ret < 0) {
104 blkio_free_mem_region(s->blkio, &s->bounce_pool);
105 memset(&s->bounce_pool, 0, sizeof(s->bounce_pool));
106 return ret;
107 }
108 }
109
110 return 0;
111}
112
113/* Called with s->bounce_lock held */
114static bool
115blkio_do_alloc_bounce_buffer(BDRVBlkioState *s, BlkioBounceBuf *bounce,
116 int64_t bytes)
117{
118 void *addr = s->bounce_pool.addr;
119 BlkioBounceBuf *cur = NULL;
120 BlkioBounceBuf *prev = NULL;
121 ptrdiff_t space;
122
123 /*
124 * This is just a linear search over the holes between requests. An
125 * efficient allocator would be nice.
126 */
127 QLIST_FOREACH(cur, &s->bounce_bufs, next) {
128 space = cur->buf.iov_base - addr;
129 if (bytes <= space) {
130 QLIST_INSERT_BEFORE(cur, bounce, next);
131 bounce->buf.iov_base = addr;
132 bounce->buf.iov_len = bytes;
133 return true;
134 }
135
136 addr = cur->buf.iov_base + cur->buf.iov_len;
137 prev = cur;
138 }
139
140 /* Is there space after the last request? */
141 space = s->bounce_pool.addr + s->bounce_pool.len - addr;
142 if (bytes > space) {
143 return false;
144 }
145 if (prev) {
146 QLIST_INSERT_AFTER(prev, bounce, next);
147 } else {
148 QLIST_INSERT_HEAD(&s->bounce_bufs, bounce, next);
149 }
150 bounce->buf.iov_base = addr;
151 bounce->buf.iov_len = bytes;
152 return true;
153}
154
155static int coroutine_fn
156blkio_alloc_bounce_buffer(BDRVBlkioState *s, BlkioBounceBuf *bounce,
157 int64_t bytes)
158{
159 /*
160 * Ensure fairness: first time around we join the back of the queue,
161 * subsequently we join the front so we don't lose our place.
162 */
163 CoQueueWaitFlags wait_flags = 0;
164
165 QEMU_LOCK_GUARD(&s->bounce_lock);
166
167 /* Ensure fairness: don't even try if other requests are already waiting */
168 if (!qemu_co_queue_empty(&s->bounce_available)) {
169 qemu_co_queue_wait_flags(&s->bounce_available, &s->bounce_lock,
170 wait_flags);
171 wait_flags = CO_QUEUE_WAIT_FRONT;
172 }
173
174 while (true) {
175 if (blkio_do_alloc_bounce_buffer(s, bounce, bytes)) {
176 /* Kick the next queued request since there may be space */
177 qemu_co_queue_next(&s->bounce_available);
178 return 0;
179 }
180
181 /*
182 * If there are no in-flight requests then the pool was simply too
183 * small.
184 */
185 if (QLIST_EMPTY(&s->bounce_bufs)) {
186 bool ok;
187 int ret;
188
189 ret = blkio_resize_bounce_pool(s, bytes);
190 if (ret < 0) {
191 /* Kick the next queued request since that may fail too */
192 qemu_co_queue_next(&s->bounce_available);
193 return ret;
194 }
195
196 ok = blkio_do_alloc_bounce_buffer(s, bounce, bytes);
197 assert(ok); /* must have space this time */
198 return 0;
199 }
200
201 qemu_co_queue_wait_flags(&s->bounce_available, &s->bounce_lock,
202 wait_flags);
203 wait_flags = CO_QUEUE_WAIT_FRONT;
204 }
205}
206
207static void coroutine_fn blkio_free_bounce_buffer(BDRVBlkioState *s,
208 BlkioBounceBuf *bounce)
209{
210 QEMU_LOCK_GUARD(&s->bounce_lock);
211
212 QLIST_REMOVE(bounce, next);
213
214 /* Wake up waiting coroutines since space may now be available */
215 qemu_co_queue_next(&s->bounce_available);
216}
217
218/* For async to .bdrv_co_*() conversion */
219typedef struct {
220 Coroutine *coroutine;
221 int ret;
222} BlkioCoData;
223
224static void blkio_completion_fd_read(void *opaque)
225{
226 BlockDriverState *bs = opaque;
227 BDRVBlkioState *s = bs->opaque;
228 uint64_t val;
229 int ret;
230
231 /* Polling may have already fetched a completion */
232 if (s->poll_completion.user_data != NULL) {
233 BlkioCoData *cod = s->poll_completion.user_data;
234 cod->ret = s->poll_completion.ret;
235
236 /* Clear it in case aio_co_wake() enters a nested event loop */
237 s->poll_completion.user_data = NULL;
238
239 aio_co_wake(cod->coroutine);
240 }
241
242 /* Reset completion fd status */
243 ret = read(s->completion_fd, &val, sizeof(val));
244
245 /* Ignore errors, there's nothing we can do */
246 (void)ret;
247
248 /*
249 * Reading one completion at a time makes nested event loop re-entrancy
250 * simple. Change this loop to get multiple completions in one go if it
251 * becomes a performance bottleneck.
252 */
253 while (true) {
254 struct blkio_completion completion;
255
256 WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
257 ret = blkioq_do_io(s->blkioq, &completion, 0, 1, NULL);
258 }
259 if (ret != 1) {
260 break;
261 }
262
263 BlkioCoData *cod = completion.user_data;
264 cod->ret = completion.ret;
265 aio_co_wake(cod->coroutine);
266 }
267}
268
269static bool blkio_completion_fd_poll(void *opaque)
270{
271 BlockDriverState *bs = opaque;
272 BDRVBlkioState *s = bs->opaque;
273 int ret;
274
275 /* Just in case we already fetched a completion */
276 if (s->poll_completion.user_data != NULL) {
277 return true;
278 }
279
280 WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
281 ret = blkioq_do_io(s->blkioq, &s->poll_completion, 0, 1, NULL);
282 }
283 return ret == 1;
284}
285
286static void blkio_completion_fd_poll_ready(void *opaque)
287{
288 blkio_completion_fd_read(opaque);
289}
290
291static void blkio_attach_aio_context(BlockDriverState *bs,
292 AioContext *new_context)
293{
294 BDRVBlkioState *s = bs->opaque;
295
296 aio_set_fd_handler(new_context,
297 s->completion_fd,
298 false,
299 blkio_completion_fd_read,
300 NULL,
301 blkio_completion_fd_poll,
302 blkio_completion_fd_poll_ready,
303 bs);
304}
305
306static void blkio_detach_aio_context(BlockDriverState *bs)
307{
308 BDRVBlkioState *s = bs->opaque;
309
310 aio_set_fd_handler(bdrv_get_aio_context(bs),
311 s->completion_fd,
312 false, NULL, NULL, NULL, NULL, NULL);
313}
314
315/* Call with s->blkio_lock held to submit I/O after enqueuing a new request */
316static void blkio_submit_io(BlockDriverState *bs)
317{
318 if (qatomic_read(&bs->io_plugged) == 0) {
319 BDRVBlkioState *s = bs->opaque;
320
321 blkioq_do_io(s->blkioq, NULL, 0, 0, NULL);
322 }
323}
324
325static int coroutine_fn
326blkio_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
327{
328 BDRVBlkioState *s = bs->opaque;
329 BlkioCoData cod = {
330 .coroutine = qemu_coroutine_self(),
331 };
332
333 WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
334 blkioq_discard(s->blkioq, offset, bytes, &cod, 0);
335 blkio_submit_io(bs);
336 }
337
338 qemu_coroutine_yield();
339 return cod.ret;
340}
341
342static int coroutine_fn
343blkio_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
344 QEMUIOVector *qiov, BdrvRequestFlags flags)
345{
346 BlkioCoData cod = {
347 .coroutine = qemu_coroutine_self(),
348 };
349 BDRVBlkioState *s = bs->opaque;
350 bool use_bounce_buffer = s->needs_mem_regions;
351 BlkioBounceBuf bounce;
352 struct iovec *iov = qiov->iov;
353 int iovcnt = qiov->niov;
354
355 if (use_bounce_buffer) {
356 int ret = blkio_alloc_bounce_buffer(s, &bounce, bytes);
357 if (ret < 0) {
358 return ret;
359 }
360
361 iov = &bounce.buf;
362 iovcnt = 1;
363 }
364
365 WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
366 blkioq_readv(s->blkioq, offset, iov, iovcnt, &cod, 0);
367 blkio_submit_io(bs);
368 }
369
370 qemu_coroutine_yield();
371
372 if (use_bounce_buffer) {
373 if (cod.ret == 0) {
374 qemu_iovec_from_buf(qiov, 0,
375 bounce.buf.iov_base,
376 bounce.buf.iov_len);
377 }
378
379 blkio_free_bounce_buffer(s, &bounce);
380 }
381
382 return cod.ret;
383}
384
385static int coroutine_fn blkio_co_pwritev(BlockDriverState *bs, int64_t offset,
386 int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
387{
388 uint32_t blkio_flags = (flags & BDRV_REQ_FUA) ? BLKIO_REQ_FUA : 0;
389 BlkioCoData cod = {
390 .coroutine = qemu_coroutine_self(),
391 };
392 BDRVBlkioState *s = bs->opaque;
393 bool use_bounce_buffer = s->needs_mem_regions;
394 BlkioBounceBuf bounce;
395 struct iovec *iov = qiov->iov;
396 int iovcnt = qiov->niov;
397
398 if (use_bounce_buffer) {
399 int ret = blkio_alloc_bounce_buffer(s, &bounce, bytes);
400 if (ret < 0) {
401 return ret;
402 }
403
404 qemu_iovec_to_buf(qiov, 0, bounce.buf.iov_base, bytes);
405 iov = &bounce.buf;
406 iovcnt = 1;
407 }
408
409 WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
410 blkioq_writev(s->blkioq, offset, iov, iovcnt, &cod, blkio_flags);
411 blkio_submit_io(bs);
412 }
413
414 qemu_coroutine_yield();
415
416 if (use_bounce_buffer) {
417 blkio_free_bounce_buffer(s, &bounce);
418 }
419
420 return cod.ret;
421}
422
423static int coroutine_fn blkio_co_flush(BlockDriverState *bs)
424{
425 BDRVBlkioState *s = bs->opaque;
426 BlkioCoData cod = {
427 .coroutine = qemu_coroutine_self(),
428 };
429
430 WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
431 blkioq_flush(s->blkioq, &cod, 0);
432 blkio_submit_io(bs);
433 }
434
435 qemu_coroutine_yield();
436 return cod.ret;
437}
438
439static int coroutine_fn blkio_co_pwrite_zeroes(BlockDriverState *bs,
440 int64_t offset, int64_t bytes, BdrvRequestFlags flags)
441{
442 BDRVBlkioState *s = bs->opaque;
443 BlkioCoData cod = {
444 .coroutine = qemu_coroutine_self(),
445 };
446 uint32_t blkio_flags = 0;
447
448 if (flags & BDRV_REQ_FUA) {
449 blkio_flags |= BLKIO_REQ_FUA;
450 }
451 if (!(flags & BDRV_REQ_MAY_UNMAP)) {
452 blkio_flags |= BLKIO_REQ_NO_UNMAP;
453 }
454 if (flags & BDRV_REQ_NO_FALLBACK) {
455 blkio_flags |= BLKIO_REQ_NO_FALLBACK;
456 }
457
458 WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
459 blkioq_write_zeroes(s->blkioq, offset, bytes, &cod, blkio_flags);
460 blkio_submit_io(bs);
461 }
462
463 qemu_coroutine_yield();
464 return cod.ret;
465}
466
467static void blkio_io_unplug(BlockDriverState *bs)
468{
469 BDRVBlkioState *s = bs->opaque;
470
471 WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
472 blkio_submit_io(bs);
473 }
474}
475
476static int blkio_io_uring_open(BlockDriverState *bs, QDict *options, int flags,
477 Error **errp)
478{
479 const char *filename = qdict_get_str(options, "filename");
480 BDRVBlkioState *s = bs->opaque;
481 int ret;
482
483 ret = blkio_set_str(s->blkio, "path", filename);
484 qdict_del(options, "filename");
485 if (ret < 0) {
486 error_setg_errno(errp, -ret, "failed to set path: %s",
487 blkio_get_error_msg());
488 return ret;
489 }
490
491 if (flags & BDRV_O_NOCACHE) {
492 ret = blkio_set_bool(s->blkio, "direct", true);
493 if (ret < 0) {
494 error_setg_errno(errp, -ret, "failed to set direct: %s",
495 blkio_get_error_msg());
496 return ret;
497 }
498 }
499
500 return 0;
501}
502
503static int blkio_nvme_io_uring(BlockDriverState *bs, QDict *options, int flags,
504 Error **errp)
505{
506 const char *filename = qdict_get_str(options, "filename");
507 BDRVBlkioState *s = bs->opaque;
508 int ret;
509
510 ret = blkio_set_str(s->blkio, "path", filename);
511 qdict_del(options, "filename");
512 if (ret < 0) {
513 error_setg_errno(errp, -ret, "failed to set path: %s",
514 blkio_get_error_msg());
515 return ret;
516 }
517
518 if (!(flags & BDRV_O_NOCACHE)) {
519 error_setg(errp, "cache.direct=off is not supported");
520 return -EINVAL;
521 }
522
523 return 0;
524}
525
526static int blkio_virtio_blk_common_open(BlockDriverState *bs,
527 QDict *options, int flags, Error **errp)
528{
529 const char *path = qdict_get_try_str(options, "path");
530 BDRVBlkioState *s = bs->opaque;
531 int ret;
532
533 if (!path) {
534 error_setg(errp, "missing 'path' option");
535 return -EINVAL;
536 }
537
538 ret = blkio_set_str(s->blkio, "path", path);
539 qdict_del(options, "path");
540 if (ret < 0) {
541 error_setg_errno(errp, -ret, "failed to set path: %s",
542 blkio_get_error_msg());
543 return ret;
544 }
545
546 if (!(flags & BDRV_O_NOCACHE)) {
547 error_setg(errp, "cache.direct=off is not supported");
548 return -EINVAL;
549 }
550 return 0;
551}
552
553static int blkio_file_open(BlockDriverState *bs, QDict *options, int flags,
554 Error **errp)
555{
556 const char *blkio_driver = bs->drv->protocol_name;
557 BDRVBlkioState *s = bs->opaque;
558 int ret;
559
560 ret = blkio_create(blkio_driver, &s->blkio);
561 if (ret < 0) {
562 error_setg_errno(errp, -ret, "blkio_create failed: %s",
563 blkio_get_error_msg());
564 return ret;
565 }
566
567 if (strcmp(blkio_driver, DRIVER_IO_URING) == 0) {
568 ret = blkio_io_uring_open(bs, options, flags, errp);
569 } else if (strcmp(blkio_driver, DRIVER_NVME_IO_URING) == 0) {
570 ret = blkio_nvme_io_uring(bs, options, flags, errp);
571 } else if (strcmp(blkio_driver, DRIVER_VIRTIO_BLK_VHOST_USER) == 0) {
572 ret = blkio_virtio_blk_common_open(bs, options, flags, errp);
573 } else if (strcmp(blkio_driver, DRIVER_VIRTIO_BLK_VHOST_VDPA) == 0) {
574 ret = blkio_virtio_blk_common_open(bs, options, flags, errp);
575 } else {
576 g_assert_not_reached();
577 }
578 if (ret < 0) {
579 blkio_destroy(&s->blkio);
580 return ret;
581 }
582
583 if (!(flags & BDRV_O_RDWR)) {
584 ret = blkio_set_bool(s->blkio, "read-only", true);
585 if (ret < 0) {
586 error_setg_errno(errp, -ret, "failed to set read-only: %s",
587 blkio_get_error_msg());
588 blkio_destroy(&s->blkio);
589 return ret;
590 }
591 }
592
593 ret = blkio_connect(s->blkio);
594 if (ret < 0) {
595 error_setg_errno(errp, -ret, "blkio_connect failed: %s",
596 blkio_get_error_msg());
597 blkio_destroy(&s->blkio);
598 return ret;
599 }
600
601 ret = blkio_get_bool(s->blkio,
602 "needs-mem-regions",
603 &s->needs_mem_regions);
604 if (ret < 0) {
605 error_setg_errno(errp, -ret,
606 "failed to get needs-mem-regions: %s",
607 blkio_get_error_msg());
608 blkio_destroy(&s->blkio);
609 return ret;
610 }
611
612 ret = blkio_get_uint64(s->blkio,
613 "mem-region-alignment",
614 &s->mem_region_alignment);
615 if (ret < 0) {
616 error_setg_errno(errp, -ret,
617 "failed to get mem-region-alignment: %s",
618 blkio_get_error_msg());
619 blkio_destroy(&s->blkio);
620 return ret;
621 }
622
623 ret = blkio_start(s->blkio);
624 if (ret < 0) {
625 error_setg_errno(errp, -ret, "blkio_start failed: %s",
626 blkio_get_error_msg());
627 blkio_destroy(&s->blkio);
628 return ret;
629 }
630
631 bs->supported_write_flags = BDRV_REQ_FUA;
632 bs->supported_zero_flags = BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP |
633 BDRV_REQ_NO_FALLBACK;
634
635 qemu_mutex_init(&s->blkio_lock);
636 qemu_co_mutex_init(&s->bounce_lock);
637 qemu_co_queue_init(&s->bounce_available);
638 QLIST_INIT(&s->bounce_bufs);
639 s->blkioq = blkio_get_queue(s->blkio, 0);
640 s->completion_fd = blkioq_get_completion_fd(s->blkioq);
641
642 blkio_attach_aio_context(bs, bdrv_get_aio_context(bs));
643 return 0;
644}
645
646static void blkio_close(BlockDriverState *bs)
647{
648 BDRVBlkioState *s = bs->opaque;
649
650 /* There is no destroy() API for s->bounce_lock */
651
652 qemu_mutex_destroy(&s->blkio_lock);
653 blkio_detach_aio_context(bs);
654 blkio_destroy(&s->blkio);
655}
656
657static int64_t blkio_getlength(BlockDriverState *bs)
658{
659 BDRVBlkioState *s = bs->opaque;
660 uint64_t capacity;
661 int ret;
662
663 WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
664 ret = blkio_get_uint64(s->blkio, "capacity", &capacity);
665 }
666 if (ret < 0) {
667 return -ret;
668 }
669
670 return capacity;
671}
672
673static int blkio_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
674{
675 return 0;
676}
677
678static void blkio_refresh_limits(BlockDriverState *bs, Error **errp)
679{
680 BDRVBlkioState *s = bs->opaque;
681 QEMU_LOCK_GUARD(&s->blkio_lock);
682 int value;
683 int ret;
684
685 ret = blkio_get_int(s->blkio, "request-alignment", &value);
686 if (ret < 0) {
687 error_setg_errno(errp, -ret, "failed to get \"request-alignment\": %s",
688 blkio_get_error_msg());
689 return;
690 }
691 bs->bl.request_alignment = value;
692 if (bs->bl.request_alignment < 1 ||
693 bs->bl.request_alignment >= INT_MAX ||
694 !is_power_of_2(bs->bl.request_alignment)) {
695 error_setg(errp, "invalid \"request-alignment\" value %" PRIu32 ", "
696 "must be a power of 2 less than INT_MAX",
697 bs->bl.request_alignment);
698 return;
699 }
700
701 ret = blkio_get_int(s->blkio, "optimal-io-size", &value);
702 if (ret < 0) {
703 error_setg_errno(errp, -ret, "failed to get \"optimal-io-size\": %s",
704 blkio_get_error_msg());
705 return;
706 }
707 bs->bl.opt_transfer = value;
708 if (bs->bl.opt_transfer > INT_MAX ||
709 (bs->bl.opt_transfer % bs->bl.request_alignment)) {
710 error_setg(errp, "invalid \"optimal-io-size\" value %" PRIu32 ", must "
711 "be a multiple of %" PRIu32, bs->bl.opt_transfer,
712 bs->bl.request_alignment);
713 return;
714 }
715
716 ret = blkio_get_int(s->blkio, "max-transfer", &value);
717 if (ret < 0) {
718 error_setg_errno(errp, -ret, "failed to get \"max-transfer\": %s",
719 blkio_get_error_msg());
720 return;
721 }
722 bs->bl.max_transfer = value;
723 if ((bs->bl.max_transfer % bs->bl.request_alignment) ||
724 (bs->bl.opt_transfer && (bs->bl.max_transfer % bs->bl.opt_transfer))) {
725 error_setg(errp, "invalid \"max-transfer\" value %" PRIu32 ", must be "
726 "a multiple of %" PRIu32 " and %" PRIu32 " (if non-zero)",
727 bs->bl.max_transfer, bs->bl.request_alignment,
728 bs->bl.opt_transfer);
729 return;
730 }
731
732 ret = blkio_get_int(s->blkio, "buf-alignment", &value);
733 if (ret < 0) {
734 error_setg_errno(errp, -ret, "failed to get \"buf-alignment\": %s",
735 blkio_get_error_msg());
736 return;
737 }
738 if (value < 1) {
739 error_setg(errp, "invalid \"buf-alignment\" value %d, must be "
740 "positive", value);
741 return;
742 }
743 bs->bl.min_mem_alignment = value;
744
745 ret = blkio_get_int(s->blkio, "optimal-buf-alignment", &value);
746 if (ret < 0) {
747 error_setg_errno(errp, -ret,
748 "failed to get \"optimal-buf-alignment\": %s",
749 blkio_get_error_msg());
750 return;
751 }
752 if (value < 1) {
753 error_setg(errp, "invalid \"optimal-buf-alignment\" value %d, "
754 "must be positive", value);
755 return;
756 }
757 bs->bl.opt_mem_alignment = value;
758
759 ret = blkio_get_int(s->blkio, "max-segments", &value);
760 if (ret < 0) {
761 error_setg_errno(errp, -ret, "failed to get \"max-segments\": %s",
762 blkio_get_error_msg());
763 return;
764 }
765 if (value < 1) {
766 error_setg(errp, "invalid \"max-segments\" value %d, must be positive",
767 value);
768 return;
769 }
770 bs->bl.max_iov = value;
771}
772
773/*
774 * TODO
775 * Missing libblkio APIs:
776 * - block_status
777 * - co_invalidate_cache
778 *
779 * Out of scope?
780 * - create
781 * - truncate
782 */
783
784#define BLKIO_DRIVER(name, ...) \
785 { \
786 .format_name = name, \
787 .protocol_name = name, \
788 .instance_size = sizeof(BDRVBlkioState), \
789 .bdrv_file_open = blkio_file_open, \
790 .bdrv_close = blkio_close, \
791 .bdrv_getlength = blkio_getlength, \
792 .bdrv_get_info = blkio_get_info, \
793 .bdrv_attach_aio_context = blkio_attach_aio_context, \
794 .bdrv_detach_aio_context = blkio_detach_aio_context, \
795 .bdrv_co_pdiscard = blkio_co_pdiscard, \
796 .bdrv_co_preadv = blkio_co_preadv, \
797 .bdrv_co_pwritev = blkio_co_pwritev, \
798 .bdrv_co_flush_to_disk = blkio_co_flush, \
799 .bdrv_co_pwrite_zeroes = blkio_co_pwrite_zeroes, \
800 .bdrv_io_unplug = blkio_io_unplug, \
801 .bdrv_refresh_limits = blkio_refresh_limits, \
802 __VA_ARGS__ \
803 }
804
805static BlockDriver bdrv_io_uring = BLKIO_DRIVER(
806 DRIVER_IO_URING,
807 .bdrv_needs_filename = true,
808);
809
810static BlockDriver bdrv_nvme_io_uring = BLKIO_DRIVER(
811 DRIVER_NVME_IO_URING,
812 .bdrv_needs_filename = true,
813);
814
815static BlockDriver bdrv_virtio_blk_vhost_user = BLKIO_DRIVER(
816 DRIVER_VIRTIO_BLK_VHOST_USER
817);
818
819static BlockDriver bdrv_virtio_blk_vhost_vdpa = BLKIO_DRIVER(
820 DRIVER_VIRTIO_BLK_VHOST_VDPA
821);
822
823static void bdrv_blkio_init(void)
824{
825 bdrv_register(&bdrv_io_uring);
826 bdrv_register(&bdrv_nvme_io_uring);
827 bdrv_register(&bdrv_virtio_blk_vhost_user);
828 bdrv_register(&bdrv_virtio_blk_vhost_vdpa);
829}
830
831block_init(bdrv_blkio_init);