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