qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

vhost-user.c (5008B)


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