xref: /qemu/hw/virtio/vhost-user-fs.c (revision 21596064081e8d0c0153f68714981c7f0e040973)
1 /*
2  * Vhost-user filesystem virtio device
3  *
4  * Copyright 2018-2019 Red Hat, Inc.
5  *
6  * Authors:
7  *  Stefan Hajnoczi <stefanha@redhat.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2 or
10  * (at your option) any later version.  See the COPYING file in the
11  * top-level directory.
12  */
13 
14 #include "qemu/osdep.h"
15 #include <sys/ioctl.h>
16 #include "standard-headers/linux/virtio_fs.h"
17 #include "qapi/error.h"
18 #include "hw/qdev-properties.h"
19 #include "hw/qdev-properties-system.h"
20 #include "hw/virtio/virtio-bus.h"
21 #include "hw/virtio/virtio-access.h"
22 #include "qemu/error-report.h"
23 #include "hw/virtio/vhost.h"
24 #include "hw/virtio/vhost-user-fs.h"
25 #include "monitor/monitor.h"
26 #include "system/system.h"
27 
28 static const int user_feature_bits[] = {
29     VIRTIO_F_VERSION_1,
30     VIRTIO_RING_F_INDIRECT_DESC,
31     VIRTIO_RING_F_EVENT_IDX,
32     VIRTIO_F_NOTIFY_ON_EMPTY,
33     VIRTIO_F_RING_PACKED,
34     VIRTIO_F_IOMMU_PLATFORM,
35     VIRTIO_F_RING_RESET,
36     VIRTIO_F_IN_ORDER,
37     VIRTIO_F_NOTIFICATION_DATA,
38     VHOST_INVALID_FEATURE_BIT
39 };
40 
vuf_get_config(VirtIODevice * vdev,uint8_t * config)41 static void vuf_get_config(VirtIODevice *vdev, uint8_t *config)
42 {
43     VHostUserFS *fs = VHOST_USER_FS(vdev);
44     struct virtio_fs_config fscfg = {};
45 
46     memcpy((char *)fscfg.tag, fs->conf.tag,
47            MIN(strlen(fs->conf.tag) + 1, sizeof(fscfg.tag)));
48 
49     virtio_stl_p(vdev, &fscfg.num_request_queues, fs->conf.num_request_queues);
50 
51     memcpy(config, &fscfg, sizeof(fscfg));
52 }
53 
vuf_start(VirtIODevice * vdev)54 static void vuf_start(VirtIODevice *vdev)
55 {
56     VHostUserFS *fs = VHOST_USER_FS(vdev);
57     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
58     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
59     int ret;
60     int i;
61 
62     if (!k->set_guest_notifiers) {
63         error_report("binding does not support guest notifiers");
64         return;
65     }
66 
67     ret = vhost_dev_enable_notifiers(&fs->vhost_dev, vdev);
68     if (ret < 0) {
69         error_report("Error enabling host notifiers: %d", -ret);
70         return;
71     }
72 
73     ret = k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, true);
74     if (ret < 0) {
75         error_report("Error binding guest notifier: %d", -ret);
76         goto err_host_notifiers;
77     }
78 
79     fs->vhost_dev.acked_features = vdev->guest_features;
80     ret = vhost_dev_start(&fs->vhost_dev, vdev, true);
81     if (ret < 0) {
82         error_report("Error starting vhost: %d", -ret);
83         goto err_guest_notifiers;
84     }
85 
86     /*
87      * guest_notifier_mask/pending not used yet, so just unmask
88      * everything here.  virtio-pci will do the right thing by
89      * enabling/disabling irqfd.
90      */
91     for (i = 0; i < fs->vhost_dev.nvqs; i++) {
92         vhost_virtqueue_mask(&fs->vhost_dev, vdev, i, false);
93     }
94 
95     return;
96 
97 err_guest_notifiers:
98     k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false);
99 err_host_notifiers:
100     vhost_dev_disable_notifiers(&fs->vhost_dev, vdev);
101 }
102 
vuf_stop(VirtIODevice * vdev)103 static int vuf_stop(VirtIODevice *vdev)
104 {
105     VHostUserFS *fs = VHOST_USER_FS(vdev);
106     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
107     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
108     int ret;
109 
110     if (!k->set_guest_notifiers) {
111         return 0;
112     }
113 
114     ret = vhost_dev_stop(&fs->vhost_dev, vdev, true);
115 
116     if (k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false) < 0) {
117         error_report("vhost guest notifier cleanup failed: %d", ret);
118         return -1;
119     }
120 
121     vhost_dev_disable_notifiers(&fs->vhost_dev, vdev);
122     return ret;
123 }
124 
vuf_set_status(VirtIODevice * vdev,uint8_t status)125 static int vuf_set_status(VirtIODevice *vdev, uint8_t status)
126 {
127     VHostUserFS *fs = VHOST_USER_FS(vdev);
128     bool should_start = virtio_device_should_start(vdev, status);
129 
130     if (vhost_dev_is_started(&fs->vhost_dev) == should_start) {
131         return 0;
132     }
133 
134     if (should_start) {
135         vuf_start(vdev);
136     } else {
137         int ret;
138         ret = vuf_stop(vdev);
139         if (ret < 0) {
140             return ret;
141         }
142     }
143     return 0;
144 }
145 
vuf_get_features(VirtIODevice * vdev,uint64_t features,Error ** errp)146 static uint64_t vuf_get_features(VirtIODevice *vdev,
147                                  uint64_t features,
148                                  Error **errp)
149 {
150     VHostUserFS *fs = VHOST_USER_FS(vdev);
151 
152     return vhost_get_features(&fs->vhost_dev, user_feature_bits, features);
153 }
154 
vuf_handle_output(VirtIODevice * vdev,VirtQueue * vq)155 static void vuf_handle_output(VirtIODevice *vdev, VirtQueue *vq)
156 {
157     /*
158      * Not normally called; it's the daemon that handles the queue;
159      * however virtio's cleanup path can call this.
160      */
161 }
162 
vuf_guest_notifier_mask(VirtIODevice * vdev,int idx,bool mask)163 static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx,
164                                             bool mask)
165 {
166     VHostUserFS *fs = VHOST_USER_FS(vdev);
167 
168     /*
169      * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1
170      * as the macro of configure interrupt's IDX, If this driver does not
171      * support, the function will return
172      */
173 
174     if (idx == VIRTIO_CONFIG_IRQ_IDX) {
175         return;
176     }
177     vhost_virtqueue_mask(&fs->vhost_dev, vdev, idx, mask);
178 }
179 
vuf_guest_notifier_pending(VirtIODevice * vdev,int idx)180 static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx)
181 {
182     VHostUserFS *fs = VHOST_USER_FS(vdev);
183 
184     /*
185      * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1
186      * as the macro of configure interrupt's IDX, If this driver does not
187      * support, the function will return
188      */
189 
190     if (idx == VIRTIO_CONFIG_IRQ_IDX) {
191         return false;
192     }
193     return vhost_virtqueue_pending(&fs->vhost_dev, idx);
194 }
195 
vuf_device_realize(DeviceState * dev,Error ** errp)196 static void vuf_device_realize(DeviceState *dev, Error **errp)
197 {
198     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
199     VHostUserFS *fs = VHOST_USER_FS(dev);
200     unsigned int i;
201     size_t len;
202     int ret;
203 
204     if (!fs->conf.chardev.chr) {
205         error_setg(errp, "missing chardev");
206         return;
207     }
208 
209     if (!fs->conf.tag) {
210         error_setg(errp, "missing tag property");
211         return;
212     }
213     len = strlen(fs->conf.tag);
214     if (len == 0) {
215         error_setg(errp, "tag property cannot be empty");
216         return;
217     }
218     if (len > sizeof_field(struct virtio_fs_config, tag)) {
219         error_setg(errp, "tag property must be %zu bytes or less",
220                    sizeof_field(struct virtio_fs_config, tag));
221         return;
222     }
223 
224     if (fs->conf.num_request_queues == 0) {
225         error_setg(errp, "num-request-queues property must be larger than 0");
226         return;
227     }
228 
229     if (!is_power_of_2(fs->conf.queue_size)) {
230         error_setg(errp, "queue-size property must be a power of 2");
231         return;
232     }
233 
234     if (fs->conf.queue_size > VIRTQUEUE_MAX_SIZE) {
235         error_setg(errp, "queue-size property must be %u or smaller",
236                    VIRTQUEUE_MAX_SIZE);
237         return;
238     }
239 
240     if (!vhost_user_init(&fs->vhost_user, &fs->conf.chardev, errp)) {
241         return;
242     }
243 
244     virtio_init(vdev, VIRTIO_ID_FS, sizeof(struct virtio_fs_config));
245 
246     /* Hiprio queue */
247     fs->hiprio_vq = virtio_add_queue(vdev, fs->conf.queue_size, vuf_handle_output);
248 
249     /* Request queues */
250     fs->req_vqs = g_new(VirtQueue *, fs->conf.num_request_queues);
251     for (i = 0; i < fs->conf.num_request_queues; i++) {
252         fs->req_vqs[i] = virtio_add_queue(vdev, fs->conf.queue_size, vuf_handle_output);
253     }
254 
255     /* 1 high prio queue, plus the number configured */
256     fs->vhost_dev.nvqs = 1 + fs->conf.num_request_queues;
257     fs->vhost_dev.vqs = g_new0(struct vhost_virtqueue, fs->vhost_dev.nvqs);
258     ret = vhost_dev_init(&fs->vhost_dev, &fs->vhost_user,
259                          VHOST_BACKEND_TYPE_USER, 0, errp);
260     if (ret < 0) {
261         goto err_virtio;
262     }
263 
264     return;
265 
266 err_virtio:
267     vhost_user_cleanup(&fs->vhost_user);
268     virtio_delete_queue(fs->hiprio_vq);
269     for (i = 0; i < fs->conf.num_request_queues; i++) {
270         virtio_delete_queue(fs->req_vqs[i]);
271     }
272     g_free(fs->req_vqs);
273     virtio_cleanup(vdev);
274     g_free(fs->vhost_dev.vqs);
275 }
276 
vuf_device_unrealize(DeviceState * dev)277 static void vuf_device_unrealize(DeviceState *dev)
278 {
279     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
280     VHostUserFS *fs = VHOST_USER_FS(dev);
281     struct vhost_virtqueue *vhost_vqs = fs->vhost_dev.vqs;
282     int i;
283 
284     /* This will stop vhost backend if appropriate. */
285     vuf_set_status(vdev, 0);
286 
287     vhost_dev_cleanup(&fs->vhost_dev);
288 
289     vhost_user_cleanup(&fs->vhost_user);
290 
291     virtio_delete_queue(fs->hiprio_vq);
292     for (i = 0; i < fs->conf.num_request_queues; i++) {
293         virtio_delete_queue(fs->req_vqs[i]);
294     }
295     g_free(fs->req_vqs);
296     virtio_cleanup(vdev);
297     g_free(vhost_vqs);
298 }
299 
vuf_get_vhost(VirtIODevice * vdev)300 static struct vhost_dev *vuf_get_vhost(VirtIODevice *vdev)
301 {
302     VHostUserFS *fs = VHOST_USER_FS(vdev);
303     return &fs->vhost_dev;
304 }
305 
306 /**
307  * Fetch the internal state from virtiofsd and save it to `f`.
308  */
vuf_save_state(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)309 static int vuf_save_state(QEMUFile *f, void *pv, size_t size,
310                           const VMStateField *field, JSONWriter *vmdesc)
311 {
312     VirtIODevice *vdev = pv;
313     VHostUserFS *fs = VHOST_USER_FS(vdev);
314     Error *local_error = NULL;
315     int ret;
316 
317     ret = vhost_save_backend_state(&fs->vhost_dev, f, &local_error);
318     if (ret < 0) {
319         error_reportf_err(local_error,
320                           "Error saving back-end state of %s device %s "
321                           "(tag: \"%s\"): ",
322                           vdev->name, vdev->parent_obj.canonical_path,
323                           fs->conf.tag ?: "<none>");
324         return ret;
325     }
326 
327     return 0;
328 }
329 
330 /**
331  * Load virtiofsd's internal state from `f` and send it over to virtiofsd.
332  */
vuf_load_state(QEMUFile * f,void * pv,size_t size,const VMStateField * field)333 static int vuf_load_state(QEMUFile *f, void *pv, size_t size,
334                           const VMStateField *field)
335 {
336     VirtIODevice *vdev = pv;
337     VHostUserFS *fs = VHOST_USER_FS(vdev);
338     Error *local_error = NULL;
339     int ret;
340 
341     ret = vhost_load_backend_state(&fs->vhost_dev, f, &local_error);
342     if (ret < 0) {
343         error_reportf_err(local_error,
344                           "Error loading back-end state of %s device %s "
345                           "(tag: \"%s\"): ",
346                           vdev->name, vdev->parent_obj.canonical_path,
347                           fs->conf.tag ?: "<none>");
348         return ret;
349     }
350 
351     return 0;
352 }
353 
vuf_is_internal_migration(void * opaque)354 static bool vuf_is_internal_migration(void *opaque)
355 {
356     /* TODO: Return false when an external migration is requested */
357     return true;
358 }
359 
vuf_check_migration_support(void * opaque)360 static int vuf_check_migration_support(void *opaque)
361 {
362     VirtIODevice *vdev = opaque;
363     VHostUserFS *fs = VHOST_USER_FS(vdev);
364 
365     if (!vhost_supports_device_state(&fs->vhost_dev)) {
366         error_report("Back-end of %s device %s (tag: \"%s\") does not support "
367                      "migration through qemu",
368                      vdev->name, vdev->parent_obj.canonical_path,
369                      fs->conf.tag ?: "<none>");
370         return -ENOTSUP;
371     }
372 
373     return 0;
374 }
375 
376 static const VMStateDescription vuf_backend_vmstate;
377 
378 static const VMStateDescription vuf_vmstate = {
379     .name = "vhost-user-fs",
380     .version_id = 0,
381     .fields = (const VMStateField[]) {
382         VMSTATE_VIRTIO_DEVICE,
383         VMSTATE_END_OF_LIST()
384     },
385     .subsections = (const VMStateDescription * const []) {
386         &vuf_backend_vmstate,
387         NULL,
388     }
389 };
390 
391 static const VMStateDescription vuf_backend_vmstate = {
392     .name = "vhost-user-fs-backend",
393     .version_id = 0,
394     .needed = vuf_is_internal_migration,
395     .pre_load = vuf_check_migration_support,
396     .pre_save = vuf_check_migration_support,
397     .fields = (const VMStateField[]) {
398         {
399             .name = "back-end",
400             .info = &(const VMStateInfo) {
401                 .name = "virtio-fs back-end state",
402                 .get = vuf_load_state,
403                 .put = vuf_save_state,
404             },
405         },
406         VMSTATE_END_OF_LIST()
407     },
408 };
409 
410 static const Property vuf_properties[] = {
411     DEFINE_PROP_CHR("chardev", VHostUserFS, conf.chardev),
412     DEFINE_PROP_STRING("tag", VHostUserFS, conf.tag),
413     DEFINE_PROP_UINT16("num-request-queues", VHostUserFS,
414                        conf.num_request_queues, 1),
415     DEFINE_PROP_UINT16("queue-size", VHostUserFS, conf.queue_size, 128),
416 };
417 
vuf_instance_init(Object * obj)418 static void vuf_instance_init(Object *obj)
419 {
420     VHostUserFS *fs = VHOST_USER_FS(obj);
421 
422     device_add_bootindex_property(obj, &fs->bootindex, "bootindex",
423                                   "/filesystem@0", DEVICE(obj));
424 }
425 
vuf_class_init(ObjectClass * klass,const void * data)426 static void vuf_class_init(ObjectClass *klass, const void *data)
427 {
428     DeviceClass *dc = DEVICE_CLASS(klass);
429     VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
430 
431     device_class_set_props(dc, vuf_properties);
432     dc->vmsd = &vuf_vmstate;
433     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
434     vdc->realize = vuf_device_realize;
435     vdc->unrealize = vuf_device_unrealize;
436     vdc->get_features = vuf_get_features;
437     vdc->get_config = vuf_get_config;
438     vdc->set_status = vuf_set_status;
439     vdc->guest_notifier_mask = vuf_guest_notifier_mask;
440     vdc->guest_notifier_pending = vuf_guest_notifier_pending;
441     vdc->get_vhost = vuf_get_vhost;
442 }
443 
444 static const TypeInfo vuf_info = {
445     .name = TYPE_VHOST_USER_FS,
446     .parent = TYPE_VIRTIO_DEVICE,
447     .instance_size = sizeof(VHostUserFS),
448     .instance_init = vuf_instance_init,
449     .class_init = vuf_class_init,
450 };
451 
vuf_register_types(void)452 static void vuf_register_types(void)
453 {
454     type_register_static(&vuf_info);
455 }
456 
457 type_init(vuf_register_types)
458