[转]qemu和vhost-user前后协商过程
转自 http://blog.chinaunix.net/uid-28541347-id-5786547.html
https://www.cnblogs.com/ck1020/p/8341914.html
https://www.cnblogs.com/ck1020/p/5939777.html virtio后端驱动
https://www.cnblogs.com/ck1020/p/6044134.html virtio前端驱动
1 static Property vhost_user_blk_properties[] = { 2 DEFINE_PROP_CHR("chardev", VHostUserBlk, chardev), 3 DEFINE_PROP_UINT16("num-queues", VHostUserBlk, num_queues, 1), 4 DEFINE_PROP_UINT32("queue-size", VHostUserBlk, queue_size, 128), 5 DEFINE_PROP_BIT("config-wce", VHostUserBlk, config_wce, 0, true), 6 DEFINE_PROP_END_OF_LIST(), 7 }; 8 9 static void vhost_user_blk_class_init(ObjectClass *klass, void *data) 10 { 11 DeviceClass *dc = DEVICE_CLASS(klass); 12 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 13 14 device_class_set_props(dc, vhost_user_blk_properties); 15 dc->vmsd = &vmstate_vhost_user_blk; 16 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 17 vdc->realize = vhost_user_blk_device_realize; 18 vdc->unrealize = vhost_user_blk_device_unrealize; 19 vdc->get_config = vhost_user_blk_update_config; 20 vdc->set_config = vhost_user_blk_set_config; 21 vdc->get_features = vhost_user_blk_get_features; 22 vdc->set_status = vhost_user_blk_set_status; 23 vdc->reset = vhost_user_blk_reset; 24 } 25 26 static const TypeInfo vhost_user_blk_info = { 27 .name = TYPE_VHOST_USER_BLK, 28 .parent = TYPE_VIRTIO_DEVICE, 29 .instance_size = sizeof(VHostUserBlk), 30 .instance_init = vhost_user_blk_instance_init, 31 .class_init = vhost_user_blk_class_init, 32 }; 33 34 static void virtio_register_types(void) 35 { 36 type_register_static(&vhost_user_blk_info); 37 } 38 39 type_init(virtio_register_types)
1 static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) 2 { 3 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 4 VHostUserBlk *s = VHOST_USER_BLK(vdev); 5 Error *err = NULL; 6 int i, ret; 7 8 if (!s->chardev.chr) { 9 error_setg(errp, "vhost-user-blk: chardev is mandatory"); 10 return; 11 } 12 13 if (!s->num_queues || s->num_queues > VIRTIO_QUEUE_MAX) { 14 error_setg(errp, "vhost-user-blk: invalid number of IO queues"); 15 return; 16 } 17 18 if (!s->queue_size) { 19 error_setg(errp, "vhost-user-blk: queue size must be non-zero"); 20 return; 21 } 22 23 if (!vhost_user_init(&s->vhost_user, &s->chardev, errp)) { 24 return; 25 } 26 27 virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, 28 sizeof(struct virtio_blk_config)); 29 30 s->virtqs = g_new(VirtQueue *, s->num_queues); 31 for (i = 0; i < s->num_queues; i++) { 32 s->virtqs[i] = virtio_add_queue(vdev, s->queue_size, 33 vhost_user_blk_handle_output); 34 } 35 36 s->inflight = g_new0(struct vhost_inflight, 1); 37 s->vhost_vqs = g_new0(struct vhost_virtqueue, s->num_queues); 38 s->watch = 0; 39 s->connected = false; 40 41 qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, 42 NULL, (void *)dev, NULL, true); 43 44 reconnect: 45 if (qemu_chr_fe_wait_connected(&s->chardev, &err) < 0) { 46 error_report_err(err); 47 goto virtio_err; 48 } 49 50 /* check whether vhost_user_blk_connect() failed or not */ 51 if (!s->connected) { 52 goto reconnect; 53 } 54 55 ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg, 56 sizeof(struct virtio_blk_config)); 57 if (ret < 0) { 58 error_report("vhost-user-blk: get block config failed"); 59 goto reconnect; 60 } 61 62 if (s->blkcfg.num_queues != s->num_queues) { 63 s->blkcfg.num_queues = s->num_queues; 64 } 65 66 return; 67 68 virtio_err: 69 g_free(s->vhost_vqs); 70 g_free(s->inflight); 71 for (i = 0; i < s->num_queues; i++) { 72 virtio_delete_queue(s->virtqs[i]); 73 } 74 g_free(s->virtqs); 75 virtio_cleanup(vdev); 76 vhost_user_cleanup(&s->vhost_user); 77 }
ss
1 static void vhost_user_blk_event(void *opaque, QEMUChrEvent event) 2 { 3 DeviceState *dev = opaque; 4 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 5 VHostUserBlk *s = VHOST_USER_BLK(vdev); 6 7 switch (event) { 8 case CHR_EVENT_OPENED://链接建立的逻辑 9 if (vhost_user_blk_connect(dev) < 0) { 10 qemu_chr_fe_disconnect(&s->chardev); 11 return; 12 } 13 s->watch = qemu_chr_fe_add_watch(&s->chardev, G_IO_HUP, 14 vhost_user_blk_watch, dev); 15 break; 16 case CHR_EVENT_CLOSED: 17 vhost_user_blk_disconnect(dev); 18 if (s->watch) { 19 g_source_remove(s->watch); 20 s->watch = 0; 21 } 22 break; 23 case CHR_EVENT_BREAK: 24 case CHR_EVENT_MUX_IN: 25 case CHR_EVENT_MUX_OUT: 26 /* Ignore */ 27 break; 28 } 29 }
1 static int vhost_user_blk_connect(DeviceState *dev) 2 { 3 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 4 VHostUserBlk *s = VHOST_USER_BLK(vdev); 5 int ret = 0; 6 7 if (s->connected) { 8 return 0; 9 } 10 s->connected = true; 11 12 s->dev.nvqs = s->num_queues; 13 s->dev.vqs = s->vhost_vqs; 14 s->dev.vq_index = 0; 15 s->dev.backend_features = 0; 16 17 vhost_dev_set_config_notifier(&s->dev, &blk_ops); 18 19 ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0); 20 if (ret < 0) { 21 error_report("vhost-user-blk: vhost initialization failed: %s", 22 strerror(-ret)); 23 return ret; 24 } 25 26 /* restore vhost state */ 27 if (virtio_device_started(vdev, vdev->status)) { 28 ret = vhost_user_blk_start(vdev); 29 if (ret < 0) { 30 error_report("vhost-user-blk: vhost start failed: %s", 31 strerror(-ret)); 32 return ret; 33 } 34 } 35 36 return 0; 37 }
vhost_dev_init
1 int vhost_dev_init(struct vhost_dev *hdev, void *opaque, 2 VhostBackendType backend_type, uint32_t busyloop_timeout) 3 { 4 uint64_t features; 5 int i, r, n_initialized_vqs = 0; 6 Error *local_err = NULL; 7 8 hdev->vdev = NULL; 9 hdev->migration_blocker = NULL; 10 11 r = vhost_set_backend_type(hdev, backend_type); 12 assert(r >= 0); 13 14 r = hdev->vhost_ops->vhost_backend_init(hdev, opaque); 15 if (r < 0) { 16 goto fail; 17 } 18 19 r = hdev->vhost_ops->vhost_set_owner(hdev); 20 if (r < 0) { 21 VHOST_OPS_DEBUG("vhost_set_owner failed"); 22 goto fail; 23 } 24 25 r = hdev->vhost_ops->vhost_get_features(hdev, &features); 26 if (r < 0) { 27 VHOST_OPS_DEBUG("vhost_get_features failed"); 28 goto fail; 29 } 30 31 for (i = 0; i < hdev->nvqs; ++i, ++n_initialized_vqs) { 32 r = vhost_virtqueue_init(hdev, hdev->vqs + i, hdev->vq_index + i); 33 if (r < 0) { 34 goto fail; 35 } 36 } 37 38 if (busyloop_timeout) { 39 for (i = 0; i < hdev->nvqs; ++i) { 40 r = vhost_virtqueue_set_busyloop_timeout(hdev, hdev->vq_index + i, 41 busyloop_timeout); 42 if (r < 0) { 43 goto fail_busyloop; 44 } 45 } 46 } 47 48 hdev->features = features; 49 50 hdev->memory_listener = (MemoryListener) { 51 .begin = vhost_begin, 52 .commit = vhost_commit, 53 .region_add = vhost_region_addnop, 54 .region_nop = vhost_region_addnop, 55 .log_start = vhost_log_start, 56 .log_stop = vhost_log_stop, 57 .log_sync = vhost_log_sync, 58 .log_global_start = vhost_log_global_start, 59 .log_global_stop = vhost_log_global_stop, 60 .eventfd_add = vhost_eventfd_add, 61 .eventfd_del = vhost_eventfd_del, 62 .priority = 10 63 }; 64 65 hdev->iommu_listener = (MemoryListener) { 66 .region_add = vhost_iommu_region_add, 67 .region_del = vhost_iommu_region_del, 68 }; 69 70 if (hdev->migration_blocker == NULL) { 71 if (!(hdev->features & (0x1ULL << VHOST_F_LOG_ALL))) { 72 error_setg(&hdev->migration_blocker, 73 "Migration disabled: vhost lacks VHOST_F_LOG_ALL feature."); 74 } else if (vhost_dev_log_is_shared(hdev) && !qemu_memfd_alloc_check()) { 75 error_setg(&hdev->migration_blocker, 76 "Migration disabled: failed to allocate shared memory"); 77 } 78 } 79 80 if (hdev->migration_blocker != NULL) { 81 r = migrate_add_blocker(hdev->migration_blocker, &local_err); 82 if (local_err) { 83 error_report_err(local_err); 84 error_free(hdev->migration_blocker); 85 goto fail_busyloop; 86 } 87 } 88 89 hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions)); 90 hdev->n_mem_sections = 0; 91 hdev->mem_sections = NULL; 92 hdev->log = NULL; 93 hdev->log_size = 0; 94 hdev->log_enabled = false; 95 hdev->started = false; 96 memory_listener_register(&hdev->memory_listener, &address_space_memory); 97 QLIST_INSERT_HEAD(&vhost_devices, hdev, entry); 98 99 if (used_memslots > hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) { 100 error_report("vhost backend memory slots limit is less" 101 " than current number of present memory slots"); 102 r = -1; 103 if (busyloop_timeout) { 104 goto fail_busyloop; 105 } else { 106 goto fail; 107 } 108 } 109 110 return 0; 111 112 fail_busyloop: 113 while (--i >= 0) { 114 vhost_virtqueue_set_busyloop_timeout(hdev, hdev->vq_index + i, 0); 115 } 116 fail: 117 hdev->nvqs = n_initialized_vqs; 118 vhost_dev_cleanup(hdev); 119 return r; 120 }
vhost_user_blk_start
dd