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 "system/vhost-user-backend.h" 19 #include "system/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 int 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; 106 107 if (!b->started) { 108 return 0; 109 } 110 111 ret = vhost_dev_stop(&b->dev, b->vdev, true); 112 113 if (k->set_guest_notifiers && 114 k->set_guest_notifiers(qbus->parent, b->dev.nvqs, false) < 0) { 115 error_report("vhost guest notifier cleanup failed: %d", ret); 116 return -1; 117 } 118 119 vhost_dev_disable_notifiers(&b->dev, b->vdev); 120 b->started = false; 121 return ret; 122 } 123 124 static void set_chardev(Object *obj, const char *value, Error **errp) 125 { 126 VhostUserBackend *b = VHOST_USER_BACKEND(obj); 127 Chardev *chr; 128 129 if (b->completed) { 130 error_setg(errp, "Property 'chardev' can no longer be set"); 131 return; 132 } 133 134 g_free(b->chr_name); 135 b->chr_name = g_strdup(value); 136 137 chr = qemu_chr_find(b->chr_name); 138 if (chr == NULL) { 139 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 140 "Chardev '%s' not found", b->chr_name); 141 return; 142 } 143 144 if (!qemu_chr_fe_init(&b->chr, chr, errp)) { 145 return; 146 } 147 148 b->completed = true; 149 /* could call vhost_dev_init() so early message can be exchanged */ 150 } 151 152 static char *get_chardev(Object *obj, Error **errp) 153 { 154 VhostUserBackend *b = VHOST_USER_BACKEND(obj); 155 Chardev *chr = qemu_chr_fe_get_driver(&b->chr); 156 157 if (chr && chr->label) { 158 return g_strdup(chr->label); 159 } 160 161 return NULL; 162 } 163 164 static void vhost_user_backend_class_init(ObjectClass *oc, const void *data) 165 { 166 object_class_property_add_str(oc, "chardev", get_chardev, set_chardev); 167 } 168 169 static void vhost_user_backend_finalize(Object *obj) 170 { 171 VhostUserBackend *b = VHOST_USER_BACKEND(obj); 172 173 g_free(b->dev.vqs); 174 g_free(b->chr_name); 175 176 vhost_user_cleanup(&b->vhost_user); 177 qemu_chr_fe_deinit(&b->chr, true); 178 } 179 180 static const TypeInfo vhost_user_backend_info = { 181 .name = TYPE_VHOST_USER_BACKEND, 182 .parent = TYPE_OBJECT, 183 .instance_size = sizeof(VhostUserBackend), 184 .class_init = vhost_user_backend_class_init, 185 .instance_finalize = vhost_user_backend_finalize, 186 }; 187 188 static void register_types(void) 189 { 190 type_register_static(&vhost_user_backend_info); 191 } 192 193 type_init(register_types); 194