1 /* 2 * QEMU vhost-user backend 3 * 4 * Copyright (C) 2018 Red Hat Inc 5 * 6 * Authors: 7 * Marc-André Lureau <marcandre.lureau@redhat.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 * See the COPYING file in the top-level directory. 11 */ 12 13 14 #include "qemu/osdep.h" 15 #include "qapi/error.h" 16 #include "qemu/error-report.h" 17 #include "qom/object_interfaces.h" 18 #include "sysemu/vhost-user-backend.h" 19 #include "sysemu/kvm.h" 20 #include "io/channel-command.h" 21 #include "hw/virtio/virtio-bus.h" 22 23 int 24 vhost_user_backend_dev_init(VhostUserBackend *b, VirtIODevice *vdev, 25 unsigned nvqs, Error **errp) 26 { 27 int ret; 28 29 assert(!b->vdev && vdev); 30 31 if (!vhost_user_init(&b->vhost_user, &b->chr, errp)) { 32 return -1; 33 } 34 35 b->vdev = vdev; 36 b->dev.nvqs = nvqs; 37 b->dev.vqs = g_new0(struct vhost_virtqueue, nvqs); 38 39 ret = vhost_dev_init(&b->dev, &b->vhost_user, VHOST_BACKEND_TYPE_USER, 0, 40 errp); 41 if (ret < 0) { 42 return -1; 43 } 44 45 return 0; 46 } 47 48 void 49 vhost_user_backend_start(VhostUserBackend *b) 50 { 51 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(b->vdev))); 52 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 53 int ret, i ; 54 55 if (b->started) { 56 return; 57 } 58 59 if (!k->set_guest_notifiers) { 60 error_report("binding does not support guest notifiers"); 61 return; 62 } 63 64 ret = vhost_dev_enable_notifiers(&b->dev, b->vdev); 65 if (ret < 0) { 66 return; 67 } 68 69 ret = k->set_guest_notifiers(qbus->parent, b->dev.nvqs, true); 70 if (ret < 0) { 71 error_report("Error binding guest notifier"); 72 goto err_host_notifiers; 73 } 74 75 b->dev.acked_features = b->vdev->guest_features; 76 ret = vhost_dev_start(&b->dev, b->vdev, true); 77 if (ret < 0) { 78 error_report("Error start vhost dev"); 79 goto err_guest_notifiers; 80 } 81 82 /* guest_notifier_mask/pending not used yet, so just unmask 83 * everything here. virtio-pci will do the right thing by 84 * enabling/disabling irqfd. 85 */ 86 for (i = 0; i < b->dev.nvqs; i++) { 87 vhost_virtqueue_mask(&b->dev, b->vdev, 88 b->dev.vq_index + i, false); 89 } 90 91 b->started = true; 92 return; 93 94 err_guest_notifiers: 95 k->set_guest_notifiers(qbus->parent, b->dev.nvqs, false); 96 err_host_notifiers: 97 vhost_dev_disable_notifiers(&b->dev, b->vdev); 98 } 99 100 void 101 vhost_user_backend_stop(VhostUserBackend *b) 102 { 103 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(b->vdev))); 104 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 105 int ret = 0; 106 107 if (!b->started) { 108 return; 109 } 110 111 vhost_dev_stop(&b->dev, b->vdev, true); 112 113 if (k->set_guest_notifiers) { 114 ret = k->set_guest_notifiers(qbus->parent, 115 b->dev.nvqs, false); 116 if (ret < 0) { 117 error_report("vhost guest notifier cleanup failed: %d", ret); 118 } 119 } 120 assert(ret >= 0); 121 122 vhost_dev_disable_notifiers(&b->dev, b->vdev); 123 b->started = false; 124 } 125 126 static void set_chardev(Object *obj, const char *value, Error **errp) 127 { 128 VhostUserBackend *b = VHOST_USER_BACKEND(obj); 129 Chardev *chr; 130 131 if (b->completed) { 132 error_setg(errp, "Property 'chardev' can no longer be set"); 133 return; 134 } 135 136 g_free(b->chr_name); 137 b->chr_name = g_strdup(value); 138 139 chr = qemu_chr_find(b->chr_name); 140 if (chr == NULL) { 141 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 142 "Chardev '%s' not found", b->chr_name); 143 return; 144 } 145 146 if (!qemu_chr_fe_init(&b->chr, chr, errp)) { 147 return; 148 } 149 150 b->completed = true; 151 /* could call vhost_dev_init() so early message can be exchanged */ 152 } 153 154 static char *get_chardev(Object *obj, Error **errp) 155 { 156 VhostUserBackend *b = VHOST_USER_BACKEND(obj); 157 Chardev *chr = qemu_chr_fe_get_driver(&b->chr); 158 159 if (chr && chr->label) { 160 return g_strdup(chr->label); 161 } 162 163 return NULL; 164 } 165 166 static void vhost_user_backend_class_init(ObjectClass *oc, void *data) 167 { 168 object_class_property_add_str(oc, "chardev", get_chardev, set_chardev); 169 } 170 171 static void vhost_user_backend_finalize(Object *obj) 172 { 173 VhostUserBackend *b = VHOST_USER_BACKEND(obj); 174 175 g_free(b->dev.vqs); 176 g_free(b->chr_name); 177 178 vhost_user_cleanup(&b->vhost_user); 179 qemu_chr_fe_deinit(&b->chr, true); 180 } 181 182 static const TypeInfo vhost_user_backend_info = { 183 .name = TYPE_VHOST_USER_BACKEND, 184 .parent = TYPE_OBJECT, 185 .instance_size = sizeof(VhostUserBackend), 186 .class_init = vhost_user_backend_class_init, 187 .instance_finalize = vhost_user_backend_finalize, 188 }; 189 190 static void register_types(void) 191 { 192 type_register_static(&vhost_user_backend_info); 193 } 194 195 type_init(register_types); 196