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