xref: /spdk/module/bdev/virtio/bdev_virtio_blk.c (revision 0ed85362c8132a2d1927757fbcade66b6660d26a)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
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
16  *       distribution.
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.
20  *
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.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "spdk/bdev.h"
37 #include "spdk/conf.h"
38 #include "spdk/endian.h"
39 #include "spdk/env.h"
40 #include "spdk/thread.h"
41 #include "spdk/string.h"
42 #include "spdk/util.h"
43 #include "spdk/json.h"
44 
45 #include "spdk_internal/assert.h"
46 #include "spdk/bdev_module.h"
47 #include "spdk_internal/log.h"
48 #include "spdk_internal/virtio.h"
49 #include "spdk_internal/vhost_user.h"
50 
51 #include <linux/virtio_blk.h>
52 
53 #include "bdev_virtio.h"
54 
55 struct virtio_blk_dev {
56 	struct virtio_dev		vdev;
57 	struct spdk_bdev		bdev;
58 	bool				readonly;
59 	bool				unmap;
60 };
61 
62 struct virtio_blk_io_ctx {
63 	struct iovec				iov_req;
64 	struct iovec				iov_resp;
65 	struct iovec				iov_unmap;
66 	struct virtio_blk_outhdr		req;
67 	struct virtio_blk_discard_write_zeroes	unmap;
68 	uint8_t					resp;
69 };
70 
71 struct bdev_virtio_blk_io_channel {
72 	struct virtio_dev		*vdev;
73 
74 	/** Virtqueue exclusively assigned to this channel. */
75 	struct virtqueue		*vq;
76 
77 	/** Virtio response poller. */
78 	struct spdk_poller		*poller;
79 };
80 
81 /* Features desired/implemented by this driver. */
82 #define VIRTIO_BLK_DEV_SUPPORTED_FEATURES		\
83 	(1ULL << VIRTIO_BLK_F_BLK_SIZE		|	\
84 	 1ULL << VIRTIO_BLK_F_TOPOLOGY		|	\
85 	 1ULL << VIRTIO_BLK_F_MQ		|	\
86 	 1ULL << VIRTIO_BLK_F_RO		|	\
87 	 1ULL << VIRTIO_BLK_F_DISCARD		|	\
88 	 1ULL << VIRTIO_RING_F_EVENT_IDX	|	\
89 	 1ULL << VHOST_USER_F_PROTOCOL_FEATURES)
90 
91 static int bdev_virtio_initialize(void);
92 static int bdev_virtio_blk_get_ctx_size(void);
93 
94 static struct spdk_bdev_module virtio_blk_if = {
95 	.name = "virtio_blk",
96 	.module_init = bdev_virtio_initialize,
97 	.get_ctx_size = bdev_virtio_blk_get_ctx_size,
98 };
99 
100 SPDK_BDEV_MODULE_REGISTER(virtio_blk, &virtio_blk_if)
101 
102 static int bdev_virtio_blk_ch_create_cb(void *io_device, void *ctx_buf);
103 static void bdev_virtio_blk_ch_destroy_cb(void *io_device, void *ctx_buf);
104 
105 static struct virtio_blk_io_ctx *
106 bdev_virtio_blk_init_io_vreq(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
107 {
108 	struct virtio_blk_outhdr *req;
109 	uint8_t *resp;
110 	struct virtio_blk_discard_write_zeroes *desc;
111 
112 	struct virtio_blk_io_ctx *io_ctx = (struct virtio_blk_io_ctx *)bdev_io->driver_ctx;
113 
114 	req = &io_ctx->req;
115 	resp = &io_ctx->resp;
116 	desc = &io_ctx->unmap;
117 
118 	io_ctx->iov_req.iov_base = req;
119 	io_ctx->iov_req.iov_len = sizeof(*req);
120 
121 	io_ctx->iov_resp.iov_base = resp;
122 	io_ctx->iov_resp.iov_len = sizeof(*resp);
123 
124 	io_ctx->iov_unmap.iov_base = desc;
125 	io_ctx->iov_unmap.iov_len = sizeof(*desc);
126 
127 	memset(req, 0, sizeof(*req));
128 	return io_ctx;
129 }
130 
131 static void
132 bdev_virtio_blk_send_io(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
133 {
134 	struct bdev_virtio_blk_io_channel *virtio_channel = spdk_io_channel_get_ctx(ch);
135 	struct virtqueue *vq = virtio_channel->vq;
136 	struct virtio_blk_io_ctx *io_ctx = (struct virtio_blk_io_ctx *)bdev_io->driver_ctx;
137 	int rc;
138 
139 	rc = virtqueue_req_start(vq, bdev_io, bdev_io->u.bdev.iovcnt + 2);
140 	if (rc == -ENOMEM) {
141 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
142 		return;
143 	} else if (rc != 0) {
144 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
145 		return;
146 	}
147 
148 	virtqueue_req_add_iovs(vq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO);
149 	if (bdev_io->type == SPDK_BDEV_IO_TYPE_UNMAP) {
150 		virtqueue_req_add_iovs(vq, &io_ctx->iov_unmap, 1, SPDK_VIRTIO_DESC_RO);
151 	} else {
152 		virtqueue_req_add_iovs(vq, bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
153 				       bdev_io->type == SPDK_BDEV_IO_TYPE_READ ?
154 				       SPDK_VIRTIO_DESC_WR : SPDK_VIRTIO_DESC_RO);
155 	}
156 	virtqueue_req_add_iovs(vq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
157 
158 	virtqueue_req_flush(vq);
159 }
160 
161 static void
162 bdev_virtio_command(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
163 {
164 	struct virtio_blk_io_ctx *io_ctx = bdev_virtio_blk_init_io_vreq(ch, bdev_io);
165 	struct virtio_blk_outhdr *req = &io_ctx->req;
166 	struct virtio_blk_discard_write_zeroes *desc = &io_ctx->unmap;
167 
168 	if (bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
169 		req->type = VIRTIO_BLK_T_IN;
170 	} else if (bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE) {
171 		req->type = VIRTIO_BLK_T_OUT;
172 	} else if (bdev_io->type == SPDK_BDEV_IO_TYPE_UNMAP) {
173 		req->type = VIRTIO_BLK_T_DISCARD;
174 		desc->sector = bdev_io->u.bdev.offset_blocks *
175 			       spdk_bdev_get_block_size(bdev_io->bdev) / 512;
176 		desc->num_sectors = bdev_io->u.bdev.num_blocks *
177 				    spdk_bdev_get_block_size(bdev_io->bdev) / 512;
178 		desc->flags = 0;
179 	}
180 
181 	req->sector = bdev_io->u.bdev.offset_blocks *
182 		      spdk_bdev_get_block_size(bdev_io->bdev) / 512;
183 
184 	bdev_virtio_blk_send_io(ch, bdev_io);
185 }
186 
187 static void
188 bdev_virtio_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
189 		       bool success)
190 {
191 	if (!success) {
192 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
193 		return;
194 	}
195 
196 	bdev_virtio_command(ch, bdev_io);
197 }
198 
199 static int
200 _bdev_virtio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
201 {
202 	struct virtio_blk_dev *bvdev = bdev_io->bdev->ctxt;
203 
204 	switch (bdev_io->type) {
205 	case SPDK_BDEV_IO_TYPE_READ:
206 		spdk_bdev_io_get_buf(bdev_io, bdev_virtio_get_buf_cb,
207 				     bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
208 		return 0;
209 	case SPDK_BDEV_IO_TYPE_WRITE:
210 		if (bvdev->readonly) {
211 			spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
212 		} else {
213 			bdev_virtio_command(ch, bdev_io);
214 		}
215 		return 0;
216 	case SPDK_BDEV_IO_TYPE_RESET:
217 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
218 		return 0;
219 	case SPDK_BDEV_IO_TYPE_UNMAP:
220 		if (bvdev->unmap) {
221 			bdev_virtio_command(ch, bdev_io);
222 		} else {
223 			spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
224 		}
225 		return 0;
226 	case SPDK_BDEV_IO_TYPE_FLUSH:
227 	default:
228 		return -1;
229 	}
230 
231 	SPDK_UNREACHABLE();
232 }
233 
234 static void
235 bdev_virtio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
236 {
237 	if (_bdev_virtio_submit_request(ch, bdev_io) < 0) {
238 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
239 	}
240 }
241 
242 static bool
243 bdev_virtio_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
244 {
245 	struct virtio_blk_dev *bvdev = ctx;
246 
247 	switch (io_type) {
248 	case SPDK_BDEV_IO_TYPE_READ:
249 	case SPDK_BDEV_IO_TYPE_RESET:
250 		return true;
251 	case SPDK_BDEV_IO_TYPE_WRITE:
252 		return !bvdev->readonly;
253 	case SPDK_BDEV_IO_TYPE_UNMAP:
254 		return bvdev->unmap;
255 	case SPDK_BDEV_IO_TYPE_FLUSH:
256 	default:
257 		return false;
258 	}
259 }
260 
261 static struct spdk_io_channel *
262 bdev_virtio_get_io_channel(void *ctx)
263 {
264 	struct virtio_blk_dev *bvdev = ctx;
265 
266 	return spdk_get_io_channel(bvdev);
267 }
268 
269 static void
270 virtio_blk_dev_unregister_cb(void *io_device)
271 {
272 	struct virtio_blk_dev *bvdev = io_device;
273 	struct virtio_dev *vdev = &bvdev->vdev;
274 
275 	virtio_dev_stop(vdev);
276 	virtio_dev_destruct(vdev);
277 	spdk_bdev_destruct_done(&bvdev->bdev, 0);
278 	free(bvdev);
279 }
280 
281 static int
282 bdev_virtio_disk_destruct(void *ctx)
283 {
284 	struct virtio_blk_dev *bvdev = ctx;
285 
286 	spdk_io_device_unregister(bvdev, virtio_blk_dev_unregister_cb);
287 	return 1;
288 }
289 
290 int
291 bdev_virtio_blk_dev_remove(const char *name, bdev_virtio_remove_cb cb_fn, void *cb_arg)
292 {
293 	struct spdk_bdev *bdev;
294 
295 	bdev = spdk_bdev_get_by_name(name);
296 	if (bdev == NULL) {
297 		return -ENODEV;
298 	}
299 
300 	if (bdev->module != &virtio_blk_if) {
301 		return -ENODEV;
302 	}
303 
304 	spdk_bdev_unregister(bdev, cb_fn, cb_arg);
305 
306 	return 0;
307 }
308 
309 static int
310 bdev_virtio_dump_json_config(void *ctx, struct spdk_json_write_ctx *w)
311 {
312 	struct virtio_blk_dev *bvdev = ctx;
313 
314 	virtio_dev_dump_json_info(&bvdev->vdev, w);
315 	return 0;
316 }
317 
318 static void
319 bdev_virtio_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
320 {
321 	struct virtio_blk_dev *bvdev = bdev->ctxt;
322 
323 	spdk_json_write_object_begin(w);
324 
325 	spdk_json_write_named_string(w, "method", "bdev_virtio_attach_controller");
326 
327 	spdk_json_write_named_object_begin(w, "params");
328 	spdk_json_write_named_string(w, "name", bvdev->vdev.name);
329 	spdk_json_write_named_string(w, "dev_type", "blk");
330 
331 	/* Write transport specific parameters. */
332 	bvdev->vdev.backend_ops->write_json_config(&bvdev->vdev, w);
333 
334 	spdk_json_write_object_end(w);
335 
336 	spdk_json_write_object_end(w);
337 }
338 
339 static const struct spdk_bdev_fn_table virtio_fn_table = {
340 	.destruct		= bdev_virtio_disk_destruct,
341 	.submit_request		= bdev_virtio_submit_request,
342 	.io_type_supported	= bdev_virtio_io_type_supported,
343 	.get_io_channel		= bdev_virtio_get_io_channel,
344 	.dump_info_json		= bdev_virtio_dump_json_config,
345 	.write_config_json	= bdev_virtio_write_config_json,
346 };
347 
348 static void
349 bdev_virtio_io_cpl(struct spdk_bdev_io *bdev_io)
350 {
351 	struct virtio_blk_io_ctx *io_ctx = (struct virtio_blk_io_ctx *)bdev_io->driver_ctx;
352 
353 	spdk_bdev_io_complete(bdev_io, io_ctx->resp == VIRTIO_BLK_S_OK ?
354 			      SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED);
355 }
356 
357 static int
358 bdev_virtio_poll(void *arg)
359 {
360 	struct bdev_virtio_blk_io_channel *ch = arg;
361 	void *io[32];
362 	uint32_t io_len[32];
363 	uint16_t i, cnt;
364 
365 	cnt = virtio_recv_pkts(ch->vq, io, io_len, SPDK_COUNTOF(io));
366 	for (i = 0; i < cnt; ++i) {
367 		bdev_virtio_io_cpl(io[i]);
368 	}
369 
370 	return cnt;
371 }
372 
373 static int
374 bdev_virtio_blk_ch_create_cb(void *io_device, void *ctx_buf)
375 {
376 	struct virtio_blk_dev *bvdev = io_device;
377 	struct virtio_dev *vdev = &bvdev->vdev;
378 	struct bdev_virtio_blk_io_channel *ch = ctx_buf;
379 	struct virtqueue *vq;
380 	int32_t queue_idx;
381 
382 	queue_idx = virtio_dev_find_and_acquire_queue(vdev, 0);
383 	if (queue_idx < 0) {
384 		SPDK_ERRLOG("Couldn't get an unused queue for the io_channel.\n");
385 		return -1;
386 	}
387 
388 	vq = vdev->vqs[queue_idx];
389 
390 	ch->vdev = vdev;
391 	ch->vq = vq;
392 
393 	ch->poller = SPDK_POLLER_REGISTER(bdev_virtio_poll, ch, 0);
394 	return 0;
395 }
396 
397 static void
398 bdev_virtio_blk_ch_destroy_cb(void *io_device, void *ctx_buf)
399 {
400 	struct virtio_blk_dev *bvdev = io_device;
401 	struct virtio_dev *vdev = &bvdev->vdev;
402 	struct bdev_virtio_blk_io_channel *ch = ctx_buf;
403 	struct virtqueue *vq = ch->vq;
404 
405 	spdk_poller_unregister(&ch->poller);
406 	virtio_dev_release_queue(vdev, vq->vq_queue_index);
407 }
408 
409 static int
410 virtio_blk_dev_init(struct virtio_blk_dev *bvdev, uint16_t max_queues)
411 {
412 	struct virtio_dev *vdev = &bvdev->vdev;
413 	struct spdk_bdev *bdev = &bvdev->bdev;
414 	uint64_t capacity, num_blocks;
415 	uint32_t block_size;
416 	uint16_t host_max_queues;
417 	int rc;
418 
419 	if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_BLK_SIZE)) {
420 		rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, blk_size),
421 						&block_size, sizeof(block_size));
422 		if (rc) {
423 			SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
424 			return rc;
425 		}
426 
427 		if (block_size == 0 || block_size % 512 != 0) {
428 			SPDK_ERRLOG("%s: invalid block size (%"PRIu32"). Must be "
429 				    "a multiple of 512.\n", vdev->name, block_size);
430 			return -EIO;
431 		}
432 	} else {
433 		block_size = 512;
434 	}
435 
436 	rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, capacity),
437 					&capacity, sizeof(capacity));
438 	if (rc) {
439 		SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
440 		return rc;
441 	}
442 
443 	/* `capacity` is a number of 512-byte sectors. */
444 	num_blocks = capacity * 512 / block_size;
445 	if (num_blocks == 0) {
446 		SPDK_ERRLOG("%s: size too small (size: %"PRIu64", blocksize: %"PRIu32").\n",
447 			    vdev->name, capacity * 512, block_size);
448 		return -EIO;
449 	}
450 
451 	if ((capacity * 512) % block_size != 0) {
452 		SPDK_WARNLOG("%s: size has been rounded down to the nearest block size boundary. "
453 			     "(block size: %"PRIu32", previous size: %"PRIu64", new size: %"PRIu64")\n",
454 			     vdev->name, block_size, capacity * 512, num_blocks * block_size);
455 	}
456 
457 	if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_MQ)) {
458 		rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
459 						&host_max_queues, sizeof(host_max_queues));
460 		if (rc) {
461 			SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
462 			return rc;
463 		}
464 	} else {
465 		host_max_queues = 1;
466 	}
467 
468 	if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_RO)) {
469 		bvdev->readonly = true;
470 	}
471 
472 	if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
473 		bvdev->unmap = true;
474 	}
475 
476 	if (max_queues == 0) {
477 		SPDK_ERRLOG("%s: requested 0 request queues (%"PRIu16" available).\n",
478 			    vdev->name, host_max_queues);
479 		return -EINVAL;
480 	}
481 
482 	if (max_queues > host_max_queues) {
483 		SPDK_WARNLOG("%s: requested %"PRIu16" request queues "
484 			     "but only %"PRIu16" available.\n",
485 			     vdev->name, max_queues, host_max_queues);
486 		max_queues = host_max_queues;
487 	}
488 
489 	/* bdev is tied with the virtio device; we can reuse the name */
490 	bdev->name = vdev->name;
491 	rc = virtio_dev_start(vdev, max_queues, 0);
492 	if (rc != 0) {
493 		return rc;
494 	}
495 
496 	bdev->product_name = "VirtioBlk Disk";
497 	bdev->write_cache = 0;
498 	bdev->blocklen = block_size;
499 	bdev->blockcnt = num_blocks;
500 
501 	bdev->ctxt = bvdev;
502 	bdev->fn_table = &virtio_fn_table;
503 	bdev->module = &virtio_blk_if;
504 
505 	spdk_io_device_register(bvdev, bdev_virtio_blk_ch_create_cb,
506 				bdev_virtio_blk_ch_destroy_cb,
507 				sizeof(struct bdev_virtio_blk_io_channel),
508 				vdev->name);
509 
510 	rc = spdk_bdev_register(bdev);
511 	if (rc) {
512 		SPDK_ERRLOG("Failed to register bdev name=%s\n", bdev->name);
513 		spdk_io_device_unregister(bvdev, NULL);
514 		virtio_dev_stop(vdev);
515 		return rc;
516 	}
517 
518 	return 0;
519 }
520 
521 static struct virtio_blk_dev *
522 virtio_pci_blk_dev_create(const char *name, struct virtio_pci_ctx *pci_ctx)
523 {
524 	static int pci_dev_counter = 0;
525 	struct virtio_blk_dev *bvdev;
526 	struct virtio_dev *vdev;
527 	char *default_name = NULL;
528 	uint16_t num_queues;
529 	int rc;
530 
531 	bvdev = calloc(1, sizeof(*bvdev));
532 	if (bvdev == NULL) {
533 		SPDK_ERRLOG("virtio device calloc failed\n");
534 		return NULL;
535 	}
536 	vdev = &bvdev->vdev;
537 
538 	if (name == NULL) {
539 		default_name = spdk_sprintf_alloc("VirtioBlk%"PRIu32, pci_dev_counter++);
540 		if (default_name == NULL) {
541 			free(vdev);
542 			return NULL;
543 		}
544 		name = default_name;
545 	}
546 
547 	rc = virtio_pci_dev_init(vdev, name, pci_ctx);
548 	free(default_name);
549 
550 	if (rc != 0) {
551 		free(bvdev);
552 		return NULL;
553 	}
554 
555 	rc = virtio_dev_reset(vdev, VIRTIO_BLK_DEV_SUPPORTED_FEATURES);
556 	if (rc != 0) {
557 		goto fail;
558 	}
559 
560 	/* TODO: add a way to limit usable virtqueues */
561 	if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_MQ)) {
562 		rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
563 						&num_queues, sizeof(num_queues));
564 		if (rc) {
565 			SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
566 			goto fail;
567 		}
568 	} else {
569 		num_queues = 1;
570 	}
571 
572 	rc = virtio_blk_dev_init(bvdev, num_queues);
573 	if (rc != 0) {
574 		goto fail;
575 	}
576 
577 	return bvdev;
578 
579 fail:
580 	vdev->ctx = NULL;
581 	virtio_dev_destruct(vdev);
582 	free(bvdev);
583 	return NULL;
584 }
585 
586 static struct virtio_blk_dev *
587 virtio_user_blk_dev_create(const char *name, const char *path,
588 			   uint16_t num_queues, uint32_t queue_size)
589 {
590 	struct virtio_blk_dev *bvdev;
591 	int rc;
592 
593 	bvdev = calloc(1, sizeof(*bvdev));
594 	if (bvdev == NULL) {
595 		SPDK_ERRLOG("calloc failed for virtio device %s: %s\n", name, path);
596 		return NULL;
597 	}
598 
599 	rc = virtio_user_dev_init(&bvdev->vdev, name, path, queue_size);
600 	if (rc != 0) {
601 		SPDK_ERRLOG("Failed to create virito device %s: %s\n", name, path);
602 		free(bvdev);
603 		return NULL;
604 	}
605 
606 	rc = virtio_dev_reset(&bvdev->vdev, VIRTIO_BLK_DEV_SUPPORTED_FEATURES);
607 	if (rc != 0) {
608 		virtio_dev_destruct(&bvdev->vdev);
609 		free(bvdev);
610 		return NULL;
611 	}
612 
613 	rc = virtio_blk_dev_init(bvdev, num_queues);
614 	if (rc != 0) {
615 		virtio_dev_destruct(&bvdev->vdev);
616 		free(bvdev);
617 		return NULL;
618 	}
619 
620 	return bvdev;
621 }
622 
623 struct bdev_virtio_pci_dev_create_ctx {
624 	const char *name;
625 	struct virtio_blk_dev *ret;
626 };
627 
628 static int
629 bdev_virtio_pci_blk_dev_create_cb(struct virtio_pci_ctx *pci_ctx, void *ctx)
630 {
631 	struct bdev_virtio_pci_dev_create_ctx *create_ctx = ctx;
632 
633 	create_ctx->ret = virtio_pci_blk_dev_create(create_ctx->name, pci_ctx);
634 	if (create_ctx->ret == NULL) {
635 		return -1;
636 	}
637 
638 	return 0;
639 }
640 
641 struct spdk_bdev *
642 bdev_virtio_pci_blk_dev_create(const char *name, struct spdk_pci_addr *pci_addr)
643 {
644 	struct bdev_virtio_pci_dev_create_ctx create_ctx;
645 
646 	create_ctx.name = name;
647 	create_ctx.ret = NULL;
648 
649 	virtio_pci_dev_attach(bdev_virtio_pci_blk_dev_create_cb, &create_ctx,
650 			      PCI_DEVICE_ID_VIRTIO_BLK_MODERN, pci_addr);
651 
652 	if (create_ctx.ret == NULL) {
653 		return NULL;
654 	}
655 
656 	return &create_ctx.ret->bdev;
657 }
658 
659 static int
660 virtio_pci_blk_dev_enumerate_cb(struct virtio_pci_ctx *pci_ctx, void *ctx)
661 {
662 	struct virtio_blk_dev *bvdev;
663 
664 	bvdev = virtio_pci_blk_dev_create(NULL, pci_ctx);
665 	return bvdev == NULL ? -1 : 0;
666 }
667 
668 static int
669 bdev_virtio_initialize(void)
670 {
671 	struct spdk_conf_section *sp;
672 	struct virtio_blk_dev *bvdev;
673 	char *default_name = NULL;
674 	char *path, *type, *name;
675 	unsigned vdev_num;
676 	int num_queues;
677 	bool enable_pci;
678 	int rc = 0;
679 
680 	for (sp = spdk_conf_first_section(NULL); sp != NULL; sp = spdk_conf_next_section(sp)) {
681 		if (!spdk_conf_section_match_prefix(sp, "VirtioUser")) {
682 			continue;
683 		}
684 
685 		if (sscanf(spdk_conf_section_get_name(sp), "VirtioUser%u", &vdev_num) != 1) {
686 			SPDK_ERRLOG("Section '%s' has non-numeric suffix.\n",
687 				    spdk_conf_section_get_name(sp));
688 			return -1;
689 		}
690 
691 		path = spdk_conf_section_get_val(sp, "Path");
692 		if (path == NULL) {
693 			SPDK_ERRLOG("VirtioUserBlk%u: missing Path\n", vdev_num);
694 			return -1;
695 		}
696 
697 		type = spdk_conf_section_get_val(sp, "Type");
698 		if (type == NULL || strcmp(type, "Blk") != 0) {
699 			continue;
700 		}
701 
702 		num_queues = spdk_conf_section_get_intval(sp, "Queues");
703 		if (num_queues < 1) {
704 			num_queues = 1;
705 		}
706 
707 		name = spdk_conf_section_get_val(sp, "Name");
708 		if (name == NULL) {
709 			default_name = spdk_sprintf_alloc("VirtioBlk%u", vdev_num);
710 			name = default_name;
711 		}
712 
713 		bvdev = virtio_user_blk_dev_create(name, path, num_queues, 512);
714 		free(default_name);
715 		default_name = NULL;
716 
717 		if (bvdev == NULL) {
718 			return -1;
719 		}
720 	}
721 
722 	sp = spdk_conf_find_section(NULL, "VirtioPci");
723 	if (sp == NULL) {
724 		return 0;
725 	}
726 
727 	enable_pci = spdk_conf_section_get_boolval(sp, "Enable", false);
728 	if (enable_pci) {
729 		rc = virtio_pci_dev_enumerate(virtio_pci_blk_dev_enumerate_cb, NULL,
730 					      PCI_DEVICE_ID_VIRTIO_BLK_MODERN);
731 	}
732 
733 	return rc;
734 }
735 
736 struct spdk_bdev *
737 bdev_virtio_user_blk_dev_create(const char *name, const char *path,
738 				unsigned num_queues, unsigned queue_size)
739 {
740 	struct virtio_blk_dev *bvdev;
741 
742 	bvdev = virtio_user_blk_dev_create(name, path, num_queues, queue_size);
743 	if (bvdev == NULL) {
744 		return NULL;
745 	}
746 
747 	return &bvdev->bdev;
748 }
749 
750 static int
751 bdev_virtio_blk_get_ctx_size(void)
752 {
753 	return sizeof(struct virtio_blk_io_ctx);
754 }
755 
756 SPDK_LOG_REGISTER_COMPONENT("virtio_blk", SPDK_LOG_VIRTIO_BLK)
757