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 "qom/object.h" 24 #include "hw/qdev-core.h" 25 #include "hw/qdev-properties.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 32 static const int user_feature_bits[] = { 33 VIRTIO_BLK_F_SIZE_MAX, 34 VIRTIO_BLK_F_SEG_MAX, 35 VIRTIO_BLK_F_GEOMETRY, 36 VIRTIO_BLK_F_BLK_SIZE, 37 VIRTIO_BLK_F_TOPOLOGY, 38 VIRTIO_BLK_F_MQ, 39 VIRTIO_BLK_F_RO, 40 VIRTIO_BLK_F_FLUSH, 41 VIRTIO_BLK_F_CONFIG_WCE, 42 VIRTIO_BLK_F_DISCARD, 43 VIRTIO_BLK_F_WRITE_ZEROES, 44 VIRTIO_F_VERSION_1, 45 VIRTIO_RING_F_INDIRECT_DESC, 46 VIRTIO_RING_F_EVENT_IDX, 47 VIRTIO_F_NOTIFY_ON_EMPTY, 48 VHOST_INVALID_FEATURE_BIT 49 }; 50 51 static void vhost_user_blk_update_config(VirtIODevice *vdev, uint8_t *config) 52 { 53 VHostUserBlk *s = VHOST_USER_BLK(vdev); 54 55 memcpy(config, &s->blkcfg, sizeof(struct virtio_blk_config)); 56 } 57 58 static void vhost_user_blk_set_config(VirtIODevice *vdev, const uint8_t *config) 59 { 60 VHostUserBlk *s = VHOST_USER_BLK(vdev); 61 struct virtio_blk_config *blkcfg = (struct virtio_blk_config *)config; 62 int ret; 63 64 if (blkcfg->wce == s->blkcfg.wce) { 65 return; 66 } 67 68 ret = vhost_dev_set_config(&s->dev, &blkcfg->wce, 69 offsetof(struct virtio_blk_config, wce), 70 sizeof(blkcfg->wce), 71 VHOST_SET_CONFIG_TYPE_MASTER); 72 if (ret) { 73 error_report("set device config space failed"); 74 return; 75 } 76 77 s->blkcfg.wce = blkcfg->wce; 78 } 79 80 static int vhost_user_blk_handle_config_change(struct vhost_dev *dev) 81 { 82 int ret; 83 struct virtio_blk_config blkcfg; 84 VHostUserBlk *s = VHOST_USER_BLK(dev->vdev); 85 86 ret = vhost_dev_get_config(dev, (uint8_t *)&blkcfg, 87 sizeof(struct virtio_blk_config)); 88 if (ret < 0) { 89 error_report("get config space failed"); 90 return -1; 91 } 92 93 /* valid for resize only */ 94 if (blkcfg.capacity != s->blkcfg.capacity) { 95 s->blkcfg.capacity = blkcfg.capacity; 96 memcpy(dev->vdev->config, &s->blkcfg, sizeof(struct virtio_blk_config)); 97 virtio_notify_config(dev->vdev); 98 } 99 100 return 0; 101 } 102 103 const VhostDevConfigOps blk_ops = { 104 .vhost_dev_config_notifier = vhost_user_blk_handle_config_change, 105 }; 106 107 static int vhost_user_blk_start(VirtIODevice *vdev) 108 { 109 VHostUserBlk *s = VHOST_USER_BLK(vdev); 110 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 111 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 112 int i, ret; 113 114 if (!k->set_guest_notifiers) { 115 error_report("binding does not support guest notifiers"); 116 return -ENOSYS; 117 } 118 119 ret = vhost_dev_enable_notifiers(&s->dev, vdev); 120 if (ret < 0) { 121 error_report("Error enabling host notifiers: %d", -ret); 122 return ret; 123 } 124 125 ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true); 126 if (ret < 0) { 127 error_report("Error binding guest notifier: %d", -ret); 128 goto err_host_notifiers; 129 } 130 131 s->dev.acked_features = vdev->guest_features; 132 133 if (!s->inflight->addr) { 134 ret = vhost_dev_get_inflight(&s->dev, s->queue_size, s->inflight); 135 if (ret < 0) { 136 error_report("Error get inflight: %d", -ret); 137 goto err_guest_notifiers; 138 } 139 } 140 141 ret = vhost_dev_set_inflight(&s->dev, s->inflight); 142 if (ret < 0) { 143 error_report("Error set inflight: %d", -ret); 144 goto err_guest_notifiers; 145 } 146 147 ret = vhost_dev_start(&s->dev, vdev); 148 if (ret < 0) { 149 error_report("Error starting vhost: %d", -ret); 150 goto err_guest_notifiers; 151 } 152 153 /* guest_notifier_mask/pending not used yet, so just unmask 154 * everything here. virtio-pci will do the right thing by 155 * enabling/disabling irqfd. 156 */ 157 for (i = 0; i < s->dev.nvqs; i++) { 158 vhost_virtqueue_mask(&s->dev, vdev, i, false); 159 } 160 161 return ret; 162 163 err_guest_notifiers: 164 k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); 165 err_host_notifiers: 166 vhost_dev_disable_notifiers(&s->dev, vdev); 167 return ret; 168 } 169 170 static void vhost_user_blk_stop(VirtIODevice *vdev) 171 { 172 VHostUserBlk *s = VHOST_USER_BLK(vdev); 173 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 174 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 175 int ret; 176 177 if (!k->set_guest_notifiers) { 178 return; 179 } 180 181 vhost_dev_stop(&s->dev, vdev); 182 183 ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); 184 if (ret < 0) { 185 error_report("vhost guest notifier cleanup failed: %d", ret); 186 return; 187 } 188 189 vhost_dev_disable_notifiers(&s->dev, vdev); 190 } 191 192 static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status) 193 { 194 VHostUserBlk *s = VHOST_USER_BLK(vdev); 195 bool should_start = virtio_device_started(vdev, status); 196 int ret; 197 198 if (!vdev->vm_running) { 199 should_start = false; 200 } 201 202 if (!s->connected) { 203 return; 204 } 205 206 if (s->dev.started == should_start) { 207 return; 208 } 209 210 if (should_start) { 211 ret = vhost_user_blk_start(vdev); 212 if (ret < 0) { 213 error_report("vhost-user-blk: vhost start failed: %s", 214 strerror(-ret)); 215 qemu_chr_fe_disconnect(&s->chardev); 216 } 217 } else { 218 vhost_user_blk_stop(vdev); 219 } 220 221 } 222 223 static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev, 224 uint64_t features, 225 Error **errp) 226 { 227 VHostUserBlk *s = VHOST_USER_BLK(vdev); 228 229 /* Turn on pre-defined features */ 230 virtio_add_feature(&features, VIRTIO_BLK_F_SEG_MAX); 231 virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY); 232 virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY); 233 virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE); 234 virtio_add_feature(&features, VIRTIO_BLK_F_FLUSH); 235 virtio_add_feature(&features, VIRTIO_BLK_F_RO); 236 virtio_add_feature(&features, VIRTIO_BLK_F_DISCARD); 237 virtio_add_feature(&features, VIRTIO_BLK_F_WRITE_ZEROES); 238 239 if (s->config_wce) { 240 virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE); 241 } 242 if (s->num_queues > 1) { 243 virtio_add_feature(&features, VIRTIO_BLK_F_MQ); 244 } 245 246 return vhost_get_features(&s->dev, user_feature_bits, features); 247 } 248 249 static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) 250 { 251 VHostUserBlk *s = VHOST_USER_BLK(vdev); 252 int i, ret; 253 254 if (!vdev->start_on_kick) { 255 return; 256 } 257 258 if (!s->connected) { 259 return; 260 } 261 262 if (s->dev.started) { 263 return; 264 } 265 266 /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start 267 * vhost here instead of waiting for .set_status(). 268 */ 269 ret = vhost_user_blk_start(vdev); 270 if (ret < 0) { 271 error_report("vhost-user-blk: vhost start failed: %s", 272 strerror(-ret)); 273 qemu_chr_fe_disconnect(&s->chardev); 274 return; 275 } 276 277 /* Kick right away to begin processing requests already in vring */ 278 for (i = 0; i < s->dev.nvqs; i++) { 279 VirtQueue *kick_vq = virtio_get_queue(vdev, i); 280 281 if (!virtio_queue_get_desc_addr(vdev, i)) { 282 continue; 283 } 284 event_notifier_set(virtio_queue_get_host_notifier(kick_vq)); 285 } 286 } 287 288 static void vhost_user_blk_reset(VirtIODevice *vdev) 289 { 290 VHostUserBlk *s = VHOST_USER_BLK(vdev); 291 292 vhost_dev_free_inflight(s->inflight); 293 } 294 295 static int vhost_user_blk_connect(DeviceState *dev) 296 { 297 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 298 VHostUserBlk *s = VHOST_USER_BLK(vdev); 299 int ret = 0; 300 301 if (s->connected) { 302 return 0; 303 } 304 s->connected = true; 305 306 s->dev.nvqs = s->num_queues; 307 s->dev.vqs = s->vqs; 308 s->dev.vq_index = 0; 309 s->dev.backend_features = 0; 310 311 vhost_dev_set_config_notifier(&s->dev, &blk_ops); 312 313 ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0); 314 if (ret < 0) { 315 error_report("vhost-user-blk: vhost initialization failed: %s", 316 strerror(-ret)); 317 return ret; 318 } 319 320 /* restore vhost state */ 321 if (virtio_device_started(vdev, vdev->status)) { 322 ret = vhost_user_blk_start(vdev); 323 if (ret < 0) { 324 error_report("vhost-user-blk: vhost start failed: %s", 325 strerror(-ret)); 326 return ret; 327 } 328 } 329 330 return 0; 331 } 332 333 static void vhost_user_blk_disconnect(DeviceState *dev) 334 { 335 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 336 VHostUserBlk *s = VHOST_USER_BLK(vdev); 337 338 if (!s->connected) { 339 return; 340 } 341 s->connected = false; 342 343 if (s->dev.started) { 344 vhost_user_blk_stop(vdev); 345 } 346 347 vhost_dev_cleanup(&s->dev); 348 } 349 350 static gboolean vhost_user_blk_watch(GIOChannel *chan, GIOCondition cond, 351 void *opaque) 352 { 353 DeviceState *dev = opaque; 354 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 355 VHostUserBlk *s = VHOST_USER_BLK(vdev); 356 357 qemu_chr_fe_disconnect(&s->chardev); 358 359 return true; 360 } 361 362 static void vhost_user_blk_event(void *opaque, int event) 363 { 364 DeviceState *dev = opaque; 365 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 366 VHostUserBlk *s = VHOST_USER_BLK(vdev); 367 368 switch (event) { 369 case CHR_EVENT_OPENED: 370 if (vhost_user_blk_connect(dev) < 0) { 371 qemu_chr_fe_disconnect(&s->chardev); 372 return; 373 } 374 s->watch = qemu_chr_fe_add_watch(&s->chardev, G_IO_HUP, 375 vhost_user_blk_watch, dev); 376 break; 377 case CHR_EVENT_CLOSED: 378 vhost_user_blk_disconnect(dev); 379 if (s->watch) { 380 g_source_remove(s->watch); 381 s->watch = 0; 382 } 383 break; 384 } 385 } 386 387 static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) 388 { 389 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 390 VHostUserBlk *s = VHOST_USER_BLK(vdev); 391 Error *err = NULL; 392 int i, ret; 393 394 if (!s->chardev.chr) { 395 error_setg(errp, "vhost-user-blk: chardev is mandatory"); 396 return; 397 } 398 399 if (!s->num_queues || s->num_queues > VIRTIO_QUEUE_MAX) { 400 error_setg(errp, "vhost-user-blk: invalid number of IO queues"); 401 return; 402 } 403 404 if (!s->queue_size) { 405 error_setg(errp, "vhost-user-blk: queue size must be non-zero"); 406 return; 407 } 408 409 if (!vhost_user_init(&s->vhost_user, &s->chardev, errp)) { 410 return; 411 } 412 413 virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, 414 sizeof(struct virtio_blk_config)); 415 416 for (i = 0; i < s->num_queues; i++) { 417 virtio_add_queue(vdev, s->queue_size, 418 vhost_user_blk_handle_output); 419 } 420 421 s->inflight = g_new0(struct vhost_inflight, 1); 422 s->vqs = g_new(struct vhost_virtqueue, s->num_queues); 423 s->watch = 0; 424 s->connected = false; 425 426 qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, 427 NULL, (void *)dev, NULL, true); 428 429 reconnect: 430 if (qemu_chr_fe_wait_connected(&s->chardev, &err) < 0) { 431 error_report_err(err); 432 goto virtio_err; 433 } 434 435 /* check whether vhost_user_blk_connect() failed or not */ 436 if (!s->connected) { 437 goto reconnect; 438 } 439 440 ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg, 441 sizeof(struct virtio_blk_config)); 442 if (ret < 0) { 443 error_report("vhost-user-blk: get block config failed"); 444 goto reconnect; 445 } 446 447 if (s->blkcfg.num_queues != s->num_queues) { 448 s->blkcfg.num_queues = s->num_queues; 449 } 450 451 return; 452 453 virtio_err: 454 g_free(s->vqs); 455 g_free(s->inflight); 456 virtio_cleanup(vdev); 457 vhost_user_cleanup(&s->vhost_user); 458 } 459 460 static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) 461 { 462 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 463 VHostUserBlk *s = VHOST_USER_BLK(dev); 464 465 virtio_set_status(vdev, 0); 466 qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, NULL, 467 NULL, NULL, NULL, false); 468 vhost_dev_cleanup(&s->dev); 469 vhost_dev_free_inflight(s->inflight); 470 g_free(s->vqs); 471 g_free(s->inflight); 472 virtio_cleanup(vdev); 473 vhost_user_cleanup(&s->vhost_user); 474 } 475 476 static void vhost_user_blk_instance_init(Object *obj) 477 { 478 VHostUserBlk *s = VHOST_USER_BLK(obj); 479 480 device_add_bootindex_property(obj, &s->bootindex, "bootindex", 481 "/disk@0,0", DEVICE(obj), NULL); 482 } 483 484 static const VMStateDescription vmstate_vhost_user_blk = { 485 .name = "vhost-user-blk", 486 .minimum_version_id = 1, 487 .version_id = 1, 488 .fields = (VMStateField[]) { 489 VMSTATE_VIRTIO_DEVICE, 490 VMSTATE_END_OF_LIST() 491 }, 492 }; 493 494 static Property vhost_user_blk_properties[] = { 495 DEFINE_PROP_CHR("chardev", VHostUserBlk, chardev), 496 DEFINE_PROP_UINT16("num-queues", VHostUserBlk, num_queues, 1), 497 DEFINE_PROP_UINT32("queue-size", VHostUserBlk, queue_size, 128), 498 DEFINE_PROP_BIT("config-wce", VHostUserBlk, config_wce, 0, true), 499 DEFINE_PROP_END_OF_LIST(), 500 }; 501 502 static void vhost_user_blk_class_init(ObjectClass *klass, void *data) 503 { 504 DeviceClass *dc = DEVICE_CLASS(klass); 505 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 506 507 dc->props = vhost_user_blk_properties; 508 dc->vmsd = &vmstate_vhost_user_blk; 509 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 510 vdc->realize = vhost_user_blk_device_realize; 511 vdc->unrealize = vhost_user_blk_device_unrealize; 512 vdc->get_config = vhost_user_blk_update_config; 513 vdc->set_config = vhost_user_blk_set_config; 514 vdc->get_features = vhost_user_blk_get_features; 515 vdc->set_status = vhost_user_blk_set_status; 516 vdc->reset = vhost_user_blk_reset; 517 } 518 519 static const TypeInfo vhost_user_blk_info = { 520 .name = TYPE_VHOST_USER_BLK, 521 .parent = TYPE_VIRTIO_DEVICE, 522 .instance_size = sizeof(VHostUserBlk), 523 .instance_init = vhost_user_blk_instance_init, 524 .class_init = vhost_user_blk_class_init, 525 }; 526 527 static void virtio_register_types(void) 528 { 529 type_register_static(&vhost_user_blk_info); 530 } 531 532 type_init(virtio_register_types) 533