1 /* 2 * vhost-user-blk host device 3 * 4 * Copyright(C) 2017 Intel Corporation. 5 * 6 * Authors: 7 * Changpeng Liu <changpeng.liu@intel.com> 8 * 9 * Largely based on the "vhost-user-scsi.c" and "vhost-scsi.c" implemented by: 10 * Felipe Franciosi <felipe@nutanix.com> 11 * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> 12 * Nicholas Bellinger <nab@risingtidesystems.com> 13 * 14 * This work is licensed under the terms of the GNU LGPL, version 2 or later. 15 * See the COPYING.LIB file in the top-level directory. 16 * 17 */ 18 19 #include "qemu/osdep.h" 20 #include "qapi/error.h" 21 #include "qemu/error-report.h" 22 #include "qemu/cutils.h" 23 #include "hw/qdev-core.h" 24 #include "hw/qdev-properties.h" 25 #include "hw/qdev-properties-system.h" 26 #include "hw/virtio/vhost.h" 27 #include "hw/virtio/vhost-user-blk.h" 28 #include "hw/virtio/virtio.h" 29 #include "hw/virtio/virtio-bus.h" 30 #include "hw/virtio/virtio-access.h" 31 #include "sysemu/sysemu.h" 32 #include "sysemu/runstate.h" 33 34 static const int user_feature_bits[] = { 35 VIRTIO_BLK_F_SIZE_MAX, 36 VIRTIO_BLK_F_SEG_MAX, 37 VIRTIO_BLK_F_GEOMETRY, 38 VIRTIO_BLK_F_BLK_SIZE, 39 VIRTIO_BLK_F_TOPOLOGY, 40 VIRTIO_BLK_F_MQ, 41 VIRTIO_BLK_F_RO, 42 VIRTIO_BLK_F_FLUSH, 43 VIRTIO_BLK_F_CONFIG_WCE, 44 VIRTIO_BLK_F_DISCARD, 45 VIRTIO_BLK_F_WRITE_ZEROES, 46 VIRTIO_F_VERSION_1, 47 VIRTIO_RING_F_INDIRECT_DESC, 48 VIRTIO_RING_F_EVENT_IDX, 49 VIRTIO_F_NOTIFY_ON_EMPTY, 50 VIRTIO_F_RING_PACKED, 51 VIRTIO_F_IOMMU_PLATFORM, 52 VHOST_INVALID_FEATURE_BIT 53 }; 54 55 static void vhost_user_blk_event(void *opaque, QEMUChrEvent event); 56 57 static void vhost_user_blk_update_config(VirtIODevice *vdev, uint8_t *config) 58 { 59 VHostUserBlk *s = VHOST_USER_BLK(vdev); 60 61 /* Our num_queues overrides the device backend */ 62 virtio_stw_p(vdev, &s->blkcfg.num_queues, s->num_queues); 63 64 memcpy(config, &s->blkcfg, sizeof(struct virtio_blk_config)); 65 } 66 67 static void vhost_user_blk_set_config(VirtIODevice *vdev, const uint8_t *config) 68 { 69 VHostUserBlk *s = VHOST_USER_BLK(vdev); 70 struct virtio_blk_config *blkcfg = (struct virtio_blk_config *)config; 71 int ret; 72 73 if (blkcfg->wce == s->blkcfg.wce) { 74 return; 75 } 76 77 ret = vhost_dev_set_config(&s->dev, &blkcfg->wce, 78 offsetof(struct virtio_blk_config, wce), 79 sizeof(blkcfg->wce), 80 VHOST_SET_CONFIG_TYPE_MASTER); 81 if (ret) { 82 error_report("set device config space failed"); 83 return; 84 } 85 86 s->blkcfg.wce = blkcfg->wce; 87 } 88 89 static int vhost_user_blk_handle_config_change(struct vhost_dev *dev) 90 { 91 int ret; 92 struct virtio_blk_config blkcfg; 93 VHostUserBlk *s = VHOST_USER_BLK(dev->vdev); 94 95 ret = vhost_dev_get_config(dev, (uint8_t *)&blkcfg, 96 sizeof(struct virtio_blk_config)); 97 if (ret < 0) { 98 error_report("get config space failed"); 99 return -1; 100 } 101 102 /* valid for resize only */ 103 if (blkcfg.capacity != s->blkcfg.capacity) { 104 s->blkcfg.capacity = blkcfg.capacity; 105 memcpy(dev->vdev->config, &s->blkcfg, sizeof(struct virtio_blk_config)); 106 virtio_notify_config(dev->vdev); 107 } 108 109 return 0; 110 } 111 112 const VhostDevConfigOps blk_ops = { 113 .vhost_dev_config_notifier = vhost_user_blk_handle_config_change, 114 }; 115 116 static int vhost_user_blk_start(VirtIODevice *vdev) 117 { 118 VHostUserBlk *s = VHOST_USER_BLK(vdev); 119 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 120 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 121 int i, ret; 122 123 if (!k->set_guest_notifiers) { 124 error_report("binding does not support guest notifiers"); 125 return -ENOSYS; 126 } 127 128 ret = vhost_dev_enable_notifiers(&s->dev, vdev); 129 if (ret < 0) { 130 error_report("Error enabling host notifiers: %d", -ret); 131 return ret; 132 } 133 134 ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true); 135 if (ret < 0) { 136 error_report("Error binding guest notifier: %d", -ret); 137 goto err_host_notifiers; 138 } 139 140 s->dev.acked_features = vdev->guest_features; 141 142 ret = vhost_dev_prepare_inflight(&s->dev, vdev); 143 if (ret < 0) { 144 error_report("Error set inflight format: %d", -ret); 145 goto err_guest_notifiers; 146 } 147 148 if (!s->inflight->addr) { 149 ret = vhost_dev_get_inflight(&s->dev, s->queue_size, s->inflight); 150 if (ret < 0) { 151 error_report("Error get inflight: %d", -ret); 152 goto err_guest_notifiers; 153 } 154 } 155 156 ret = vhost_dev_set_inflight(&s->dev, s->inflight); 157 if (ret < 0) { 158 error_report("Error set inflight: %d", -ret); 159 goto err_guest_notifiers; 160 } 161 162 ret = vhost_dev_start(&s->dev, vdev); 163 if (ret < 0) { 164 error_report("Error starting vhost: %d", -ret); 165 goto err_guest_notifiers; 166 } 167 s->started_vu = true; 168 169 /* guest_notifier_mask/pending not used yet, so just unmask 170 * everything here. virtio-pci will do the right thing by 171 * enabling/disabling irqfd. 172 */ 173 for (i = 0; i < s->dev.nvqs; i++) { 174 vhost_virtqueue_mask(&s->dev, vdev, i, false); 175 } 176 177 return ret; 178 179 err_guest_notifiers: 180 k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); 181 err_host_notifiers: 182 vhost_dev_disable_notifiers(&s->dev, vdev); 183 return ret; 184 } 185 186 static void vhost_user_blk_stop(VirtIODevice *vdev) 187 { 188 VHostUserBlk *s = VHOST_USER_BLK(vdev); 189 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 190 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 191 int ret; 192 193 if (!s->started_vu) { 194 return; 195 } 196 s->started_vu = false; 197 198 if (!k->set_guest_notifiers) { 199 return; 200 } 201 202 vhost_dev_stop(&s->dev, vdev); 203 204 ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); 205 if (ret < 0) { 206 error_report("vhost guest notifier cleanup failed: %d", ret); 207 return; 208 } 209 210 vhost_dev_disable_notifiers(&s->dev, vdev); 211 } 212 213 static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status) 214 { 215 VHostUserBlk *s = VHOST_USER_BLK(vdev); 216 bool should_start = virtio_device_started(vdev, status); 217 int ret; 218 219 if (!vdev->vm_running) { 220 should_start = false; 221 } 222 223 if (!s->connected) { 224 return; 225 } 226 227 if (s->dev.started == should_start) { 228 return; 229 } 230 231 if (should_start) { 232 ret = vhost_user_blk_start(vdev); 233 if (ret < 0) { 234 error_report("vhost-user-blk: vhost start failed: %s", 235 strerror(-ret)); 236 qemu_chr_fe_disconnect(&s->chardev); 237 } 238 } else { 239 vhost_user_blk_stop(vdev); 240 } 241 242 } 243 244 static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev, 245 uint64_t features, 246 Error **errp) 247 { 248 VHostUserBlk *s = VHOST_USER_BLK(vdev); 249 250 /* Turn on pre-defined features */ 251 virtio_add_feature(&features, VIRTIO_BLK_F_SEG_MAX); 252 virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY); 253 virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY); 254 virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE); 255 virtio_add_feature(&features, VIRTIO_BLK_F_FLUSH); 256 virtio_add_feature(&features, VIRTIO_BLK_F_RO); 257 virtio_add_feature(&features, VIRTIO_BLK_F_DISCARD); 258 virtio_add_feature(&features, VIRTIO_BLK_F_WRITE_ZEROES); 259 260 if (s->config_wce) { 261 virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE); 262 } 263 if (s->num_queues > 1) { 264 virtio_add_feature(&features, VIRTIO_BLK_F_MQ); 265 } 266 267 return vhost_get_features(&s->dev, user_feature_bits, features); 268 } 269 270 static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) 271 { 272 VHostUserBlk *s = VHOST_USER_BLK(vdev); 273 int i, ret; 274 275 if (!vdev->start_on_kick) { 276 return; 277 } 278 279 if (!s->connected) { 280 return; 281 } 282 283 if (s->dev.started) { 284 return; 285 } 286 287 /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start 288 * vhost here instead of waiting for .set_status(). 289 */ 290 ret = vhost_user_blk_start(vdev); 291 if (ret < 0) { 292 error_report("vhost-user-blk: vhost start failed: %s", 293 strerror(-ret)); 294 qemu_chr_fe_disconnect(&s->chardev); 295 return; 296 } 297 298 /* Kick right away to begin processing requests already in vring */ 299 for (i = 0; i < s->dev.nvqs; i++) { 300 VirtQueue *kick_vq = virtio_get_queue(vdev, i); 301 302 if (!virtio_queue_get_desc_addr(vdev, i)) { 303 continue; 304 } 305 event_notifier_set(virtio_queue_get_host_notifier(kick_vq)); 306 } 307 } 308 309 static void vhost_user_blk_reset(VirtIODevice *vdev) 310 { 311 VHostUserBlk *s = VHOST_USER_BLK(vdev); 312 313 vhost_dev_free_inflight(s->inflight); 314 } 315 316 static int vhost_user_blk_connect(DeviceState *dev, Error **errp) 317 { 318 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 319 VHostUserBlk *s = VHOST_USER_BLK(vdev); 320 int ret = 0; 321 322 if (s->connected) { 323 return 0; 324 } 325 s->connected = true; 326 327 s->dev.num_queues = s->num_queues; 328 s->dev.nvqs = s->num_queues; 329 s->dev.vqs = s->vhost_vqs; 330 s->dev.vq_index = 0; 331 s->dev.backend_features = 0; 332 333 vhost_dev_set_config_notifier(&s->dev, &blk_ops); 334 335 ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0); 336 if (ret < 0) { 337 error_setg_errno(errp, -ret, "vhost initialization failed"); 338 return ret; 339 } 340 341 /* restore vhost state */ 342 if (virtio_device_started(vdev, vdev->status)) { 343 ret = vhost_user_blk_start(vdev); 344 if (ret < 0) { 345 error_setg_errno(errp, -ret, "vhost start failed"); 346 return ret; 347 } 348 } 349 350 return 0; 351 } 352 353 static void vhost_user_blk_disconnect(DeviceState *dev) 354 { 355 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 356 VHostUserBlk *s = VHOST_USER_BLK(vdev); 357 358 if (!s->connected) { 359 return; 360 } 361 s->connected = false; 362 363 vhost_user_blk_stop(vdev); 364 365 vhost_dev_cleanup(&s->dev); 366 } 367 368 static void vhost_user_blk_chr_closed_bh(void *opaque) 369 { 370 DeviceState *dev = opaque; 371 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 372 VHostUserBlk *s = VHOST_USER_BLK(vdev); 373 374 vhost_user_blk_disconnect(dev); 375 qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, 376 NULL, opaque, NULL, true); 377 } 378 379 static void vhost_user_blk_event(void *opaque, QEMUChrEvent event) 380 { 381 DeviceState *dev = opaque; 382 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 383 VHostUserBlk *s = VHOST_USER_BLK(vdev); 384 Error *local_err = NULL; 385 386 switch (event) { 387 case CHR_EVENT_OPENED: 388 if (vhost_user_blk_connect(dev, &local_err) < 0) { 389 error_report_err(local_err); 390 qemu_chr_fe_disconnect(&s->chardev); 391 return; 392 } 393 break; 394 case CHR_EVENT_CLOSED: 395 if (!runstate_check(RUN_STATE_SHUTDOWN)) { 396 /* 397 * A close event may happen during a read/write, but vhost 398 * code assumes the vhost_dev remains setup, so delay the 399 * stop & clear. 400 */ 401 AioContext *ctx = qemu_get_current_aio_context(); 402 403 qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, NULL, NULL, 404 NULL, NULL, false); 405 aio_bh_schedule_oneshot(ctx, vhost_user_blk_chr_closed_bh, opaque); 406 407 /* 408 * Move vhost device to the stopped state. The vhost-user device 409 * will be clean up and disconnected in BH. This can be useful in 410 * the vhost migration code. If disconnect was caught there is an 411 * option for the general vhost code to get the dev state without 412 * knowing its type (in this case vhost-user). 413 */ 414 s->dev.started = false; 415 } 416 break; 417 case CHR_EVENT_BREAK: 418 case CHR_EVENT_MUX_IN: 419 case CHR_EVENT_MUX_OUT: 420 /* Ignore */ 421 break; 422 } 423 } 424 425 static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) 426 { 427 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 428 VHostUserBlk *s = VHOST_USER_BLK(vdev); 429 int i, ret; 430 431 if (!s->chardev.chr) { 432 error_setg(errp, "chardev is mandatory"); 433 return; 434 } 435 436 if (s->num_queues == VHOST_USER_BLK_AUTO_NUM_QUEUES) { 437 s->num_queues = 1; 438 } 439 if (!s->num_queues || s->num_queues > VIRTIO_QUEUE_MAX) { 440 error_setg(errp, "invalid number of IO queues"); 441 return; 442 } 443 444 if (!s->queue_size) { 445 error_setg(errp, "queue size must be non-zero"); 446 return; 447 } 448 if (s->queue_size > VIRTQUEUE_MAX_SIZE) { 449 error_setg(errp, "queue size must not exceed %d", 450 VIRTQUEUE_MAX_SIZE); 451 return; 452 } 453 454 if (!vhost_user_init(&s->vhost_user, &s->chardev, errp)) { 455 return; 456 } 457 458 virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, 459 sizeof(struct virtio_blk_config)); 460 461 s->virtqs = g_new(VirtQueue *, s->num_queues); 462 for (i = 0; i < s->num_queues; i++) { 463 s->virtqs[i] = virtio_add_queue(vdev, s->queue_size, 464 vhost_user_blk_handle_output); 465 } 466 467 s->inflight = g_new0(struct vhost_inflight, 1); 468 s->vhost_vqs = g_new0(struct vhost_virtqueue, s->num_queues); 469 s->connected = false; 470 471 if (qemu_chr_fe_wait_connected(&s->chardev, errp) < 0) { 472 goto virtio_err; 473 } 474 475 if (vhost_user_blk_connect(dev, errp) < 0) { 476 qemu_chr_fe_disconnect(&s->chardev); 477 goto virtio_err; 478 } 479 assert(s->connected); 480 481 ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg, 482 sizeof(struct virtio_blk_config)); 483 if (ret < 0) { 484 error_setg(errp, "vhost-user-blk: get block config failed"); 485 goto vhost_err; 486 } 487 488 /* we're fully initialized, now we can operate, so add the handler */ 489 qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, 490 vhost_user_blk_event, NULL, (void *)dev, 491 NULL, true); 492 return; 493 494 vhost_err: 495 vhost_dev_cleanup(&s->dev); 496 virtio_err: 497 g_free(s->vhost_vqs); 498 s->vhost_vqs = NULL; 499 g_free(s->inflight); 500 s->inflight = NULL; 501 for (i = 0; i < s->num_queues; i++) { 502 virtio_delete_queue(s->virtqs[i]); 503 } 504 g_free(s->virtqs); 505 virtio_cleanup(vdev); 506 vhost_user_cleanup(&s->vhost_user); 507 } 508 509 static void vhost_user_blk_device_unrealize(DeviceState *dev) 510 { 511 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 512 VHostUserBlk *s = VHOST_USER_BLK(dev); 513 int i; 514 515 virtio_set_status(vdev, 0); 516 qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, NULL, 517 NULL, NULL, NULL, false); 518 vhost_dev_cleanup(&s->dev); 519 vhost_dev_free_inflight(s->inflight); 520 g_free(s->vhost_vqs); 521 s->vhost_vqs = NULL; 522 g_free(s->inflight); 523 s->inflight = NULL; 524 525 for (i = 0; i < s->num_queues; i++) { 526 virtio_delete_queue(s->virtqs[i]); 527 } 528 g_free(s->virtqs); 529 virtio_cleanup(vdev); 530 vhost_user_cleanup(&s->vhost_user); 531 } 532 533 static void vhost_user_blk_instance_init(Object *obj) 534 { 535 VHostUserBlk *s = VHOST_USER_BLK(obj); 536 537 device_add_bootindex_property(obj, &s->bootindex, "bootindex", 538 "/disk@0,0", DEVICE(obj)); 539 } 540 541 static const VMStateDescription vmstate_vhost_user_blk = { 542 .name = "vhost-user-blk", 543 .minimum_version_id = 1, 544 .version_id = 1, 545 .fields = (VMStateField[]) { 546 VMSTATE_VIRTIO_DEVICE, 547 VMSTATE_END_OF_LIST() 548 }, 549 }; 550 551 static Property vhost_user_blk_properties[] = { 552 DEFINE_PROP_CHR("chardev", VHostUserBlk, chardev), 553 DEFINE_PROP_UINT16("num-queues", VHostUserBlk, num_queues, 554 VHOST_USER_BLK_AUTO_NUM_QUEUES), 555 DEFINE_PROP_UINT32("queue-size", VHostUserBlk, queue_size, 128), 556 DEFINE_PROP_BIT("config-wce", VHostUserBlk, config_wce, 0, true), 557 DEFINE_PROP_END_OF_LIST(), 558 }; 559 560 static void vhost_user_blk_class_init(ObjectClass *klass, void *data) 561 { 562 DeviceClass *dc = DEVICE_CLASS(klass); 563 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 564 565 device_class_set_props(dc, vhost_user_blk_properties); 566 dc->vmsd = &vmstate_vhost_user_blk; 567 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 568 vdc->realize = vhost_user_blk_device_realize; 569 vdc->unrealize = vhost_user_blk_device_unrealize; 570 vdc->get_config = vhost_user_blk_update_config; 571 vdc->set_config = vhost_user_blk_set_config; 572 vdc->get_features = vhost_user_blk_get_features; 573 vdc->set_status = vhost_user_blk_set_status; 574 vdc->reset = vhost_user_blk_reset; 575 } 576 577 static const TypeInfo vhost_user_blk_info = { 578 .name = TYPE_VHOST_USER_BLK, 579 .parent = TYPE_VIRTIO_DEVICE, 580 .instance_size = sizeof(VHostUserBlk), 581 .instance_init = vhost_user_blk_instance_init, 582 .class_init = vhost_user_blk_class_init, 583 }; 584 585 static void virtio_register_types(void) 586 { 587 type_register_static(&vhost_user_blk_info); 588 } 589 590 type_init(virtio_register_types) 591