xref: /qemu/hw/9pfs/virtio-9p-device.c (revision 2a0c56aa4c3e9a9f0b7678015ef96afe3e841506)
1f4f61d27SAneesh Kumar K.V /*
2f4f61d27SAneesh Kumar K.V  * Virtio 9p backend
3f4f61d27SAneesh Kumar K.V  *
4f4f61d27SAneesh Kumar K.V  * Copyright IBM, Corp. 2010
5f4f61d27SAneesh Kumar K.V  *
6f4f61d27SAneesh Kumar K.V  * Authors:
7f4f61d27SAneesh Kumar K.V  *  Anthony Liguori   <aliguori@us.ibm.com>
8f4f61d27SAneesh Kumar K.V  *
9f4f61d27SAneesh Kumar K.V  * This work is licensed under the terms of the GNU GPL, version 2.  See
10f4f61d27SAneesh Kumar K.V  * the COPYING file in the top-level directory.
11f4f61d27SAneesh Kumar K.V  *
12f4f61d27SAneesh Kumar K.V  */
13f4f61d27SAneesh Kumar K.V 
140d09e41aSPaolo Bonzini #include "hw/virtio/virtio.h"
150d09e41aSPaolo Bonzini #include "hw/i386/pc.h"
161de7afc9SPaolo Bonzini #include "qemu/sockets.h"
17f4f61d27SAneesh Kumar K.V #include "virtio-9p.h"
18f4f61d27SAneesh Kumar K.V #include "fsdev/qemu-fsdev.h"
19267ae092SWei Liu #include "9p-xattr.h"
20fe52840cSWei Liu #include "coth.h"
21d64ccb91SGreg Kurz #include "hw/virtio/virtio-access.h"
220192cc5dSWei Liu #include "qemu/iov.h"
23f4f61d27SAneesh Kumar K.V 
240d3716b4SWei Liu void virtio_9p_push_and_notify(V9fsPDU *pdu)
250d3716b4SWei Liu {
260d3716b4SWei Liu     V9fsState *s = pdu->s;
270d3716b4SWei Liu 
280d3716b4SWei Liu     /* push onto queue and notify */
290d3716b4SWei Liu     virtqueue_push(s->vq, &pdu->elem, pdu->size);
300d3716b4SWei Liu 
310d3716b4SWei Liu     /* FIXME: we should batch these completions */
320d3716b4SWei Liu     virtio_notify(VIRTIO_DEVICE(s), s->vq);
330d3716b4SWei Liu }
340d3716b4SWei Liu 
350192cc5dSWei Liu static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
360192cc5dSWei Liu {
370192cc5dSWei Liu     V9fsState *s = (V9fsState *)vdev;
380192cc5dSWei Liu     V9fsPDU *pdu;
390192cc5dSWei Liu     ssize_t len;
400192cc5dSWei Liu 
410192cc5dSWei Liu     while ((pdu = pdu_alloc(s)) &&
420192cc5dSWei Liu             (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
430192cc5dSWei Liu         struct {
440192cc5dSWei Liu             uint32_t size_le;
450192cc5dSWei Liu             uint8_t id;
460192cc5dSWei Liu             uint16_t tag_le;
470192cc5dSWei Liu         } QEMU_PACKED out;
480192cc5dSWei Liu         int len;
490192cc5dSWei Liu 
500192cc5dSWei Liu         BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
510192cc5dSWei Liu         QEMU_BUILD_BUG_ON(sizeof out != 7);
520192cc5dSWei Liu 
530192cc5dSWei Liu         len = iov_to_buf(pdu->elem.out_sg, pdu->elem.out_num, 0,
540192cc5dSWei Liu                          &out, sizeof out);
550192cc5dSWei Liu         BUG_ON(len != sizeof out);
560192cc5dSWei Liu 
570192cc5dSWei Liu         pdu->size = le32_to_cpu(out.size_le);
580192cc5dSWei Liu 
590192cc5dSWei Liu         pdu->id = out.id;
600192cc5dSWei Liu         pdu->tag = le16_to_cpu(out.tag_le);
610192cc5dSWei Liu 
620192cc5dSWei Liu         qemu_co_queue_init(&pdu->complete);
630192cc5dSWei Liu         pdu_submit(pdu);
640192cc5dSWei Liu     }
650192cc5dSWei Liu     pdu_free(pdu);
660192cc5dSWei Liu }
670192cc5dSWei Liu 
689d5b731dSJason Wang static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features,
699d5b731dSJason Wang                                        Error **errp)
70f4f61d27SAneesh Kumar K.V {
710cd09c3aSCornelia Huck     virtio_add_feature(&features, VIRTIO_9P_MOUNT_TAG);
72f4f61d27SAneesh Kumar K.V     return features;
73f4f61d27SAneesh Kumar K.V }
74f4f61d27SAneesh Kumar K.V 
75f4f61d27SAneesh Kumar K.V static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
76f4f61d27SAneesh Kumar K.V {
77e9a0152bSAneesh Kumar K.V     int len;
78f4f61d27SAneesh Kumar K.V     struct virtio_9p_config *cfg;
7913daf6caSKONRAD Frederic     V9fsState *s = VIRTIO_9P(vdev);
80f4f61d27SAneesh Kumar K.V 
81e9a0152bSAneesh Kumar K.V     len = strlen(s->tag);
82e9a0152bSAneesh Kumar K.V     cfg = g_malloc0(sizeof(struct virtio_9p_config) + len);
83d64ccb91SGreg Kurz     virtio_stw_p(vdev, &cfg->tag_len, len);
84e9a0152bSAneesh Kumar K.V     /* We don't copy the terminating null to config space */
85e9a0152bSAneesh Kumar K.V     memcpy(cfg->tag, s->tag, len);
86f4f61d27SAneesh Kumar K.V     memcpy(config, cfg, s->config_size);
877267c094SAnthony Liguori     g_free(cfg);
88f4f61d27SAneesh Kumar K.V }
89f4f61d27SAneesh Kumar K.V 
904652f164SGreg Kurz static void virtio_9p_save(QEMUFile *f, void *opaque)
914652f164SGreg Kurz {
924652f164SGreg Kurz     virtio_save(VIRTIO_DEVICE(opaque), f);
934652f164SGreg Kurz }
944652f164SGreg Kurz 
954652f164SGreg Kurz static int virtio_9p_load(QEMUFile *f, void *opaque, int version_id)
964652f164SGreg Kurz {
974652f164SGreg Kurz     return virtio_load(VIRTIO_DEVICE(opaque), f, version_id);
984652f164SGreg Kurz }
994652f164SGreg Kurz 
10059be7522SAndreas Färber static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
101f4f61d27SAneesh Kumar K.V {
10259be7522SAndreas Färber     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
10359be7522SAndreas Färber     V9fsState *s = VIRTIO_9P(dev);
104f4f61d27SAneesh Kumar K.V 
105*2a0c56aaSWei Liu     if (v9fs_device_realize_common(s, errp)) {
106*2a0c56aaSWei Liu         goto out;
107f4f61d27SAneesh Kumar K.V     }
108f4f61d27SAneesh Kumar K.V 
109*2a0c56aaSWei Liu     s->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag);
110*2a0c56aaSWei Liu     virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, s->config_size);
111e8111e50SKONRAD Frederic     s->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output);
1124652f164SGreg Kurz     register_savevm(dev, "virtio-9p", -1, 1, virtio_9p_save, virtio_9p_load, s);
113*2a0c56aaSWei Liu 
11492304bf3SM. Mohan Kumar out:
115*2a0c56aaSWei Liu     return;
116e7303c43SKONRAD Frederic }
117e7303c43SKONRAD Frederic 
1186cecf093SGreg Kurz static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp)
1196cecf093SGreg Kurz {
1206cecf093SGreg Kurz     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
1216cecf093SGreg Kurz     V9fsState *s = VIRTIO_9P(dev);
1226cecf093SGreg Kurz 
1236cecf093SGreg Kurz     virtio_cleanup(vdev);
1246cecf093SGreg Kurz     unregister_savevm(dev, "virtio-9p", s);
125*2a0c56aaSWei Liu     v9fs_device_unrealize_common(s, errp);
1266cecf093SGreg Kurz }
1276cecf093SGreg Kurz 
128fe9fa96dSWei Liu ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset,
129fe9fa96dSWei Liu                             const char *fmt, va_list ap)
130fe9fa96dSWei Liu {
131fe9fa96dSWei Liu     return v9fs_iov_vmarshal(pdu->elem.in_sg, pdu->elem.in_num,
132fe9fa96dSWei Liu                              offset, 1, fmt, ap);
133fe9fa96dSWei Liu }
134fe9fa96dSWei Liu 
135fe9fa96dSWei Liu ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
136fe9fa96dSWei Liu                               const char *fmt, va_list ap)
137fe9fa96dSWei Liu {
138fe9fa96dSWei Liu     return v9fs_iov_vunmarshal(pdu->elem.out_sg, pdu->elem.out_num,
139fe9fa96dSWei Liu                                offset, 1, fmt, ap);
140fe9fa96dSWei Liu }
141fe9fa96dSWei Liu 
142592707afSWei Liu void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
143592707afSWei Liu                               unsigned int *pniov, bool is_write)
144592707afSWei Liu {
145592707afSWei Liu     if (is_write) {
146592707afSWei Liu         *piov = pdu->elem.out_sg;
147592707afSWei Liu         *pniov = pdu->elem.out_num;
148592707afSWei Liu     } else {
149592707afSWei Liu         *piov = pdu->elem.in_sg;
150592707afSWei Liu         *pniov = pdu->elem.in_num;
151592707afSWei Liu     }
152592707afSWei Liu }
153592707afSWei Liu 
154e7303c43SKONRAD Frederic /* virtio-9p device */
155e7303c43SKONRAD Frederic 
156e7303c43SKONRAD Frederic static Property virtio_9p_properties[] = {
15783a84878SShannon Zhao     DEFINE_PROP_STRING("mount_tag", V9fsState, fsconf.tag),
15883a84878SShannon Zhao     DEFINE_PROP_STRING("fsdev", V9fsState, fsconf.fsdev_id),
159e7303c43SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
160e7303c43SKONRAD Frederic };
161e7303c43SKONRAD Frederic 
162e7303c43SKONRAD Frederic static void virtio_9p_class_init(ObjectClass *klass, void *data)
163e7303c43SKONRAD Frederic {
164e7303c43SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
165e7303c43SKONRAD Frederic     VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
16659be7522SAndreas Färber 
167e7303c43SKONRAD Frederic     dc->props = virtio_9p_properties;
168125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
16959be7522SAndreas Färber     vdc->realize = virtio_9p_device_realize;
1706cecf093SGreg Kurz     vdc->unrealize = virtio_9p_device_unrealize;
171e7303c43SKONRAD Frederic     vdc->get_features = virtio_9p_get_features;
172e7303c43SKONRAD Frederic     vdc->get_config = virtio_9p_get_config;
173e7303c43SKONRAD Frederic }
174e7303c43SKONRAD Frederic 
175e7303c43SKONRAD Frederic static const TypeInfo virtio_device_info = {
176e7303c43SKONRAD Frederic     .name = TYPE_VIRTIO_9P,
177e7303c43SKONRAD Frederic     .parent = TYPE_VIRTIO_DEVICE,
178e7303c43SKONRAD Frederic     .instance_size = sizeof(V9fsState),
179e7303c43SKONRAD Frederic     .class_init = virtio_9p_class_init,
180e7303c43SKONRAD Frederic };
181e7303c43SKONRAD Frederic 
182e7303c43SKONRAD Frederic static void virtio_9p_register_types(void)
183e7303c43SKONRAD Frederic {
184e7303c43SKONRAD Frederic     type_register_static(&virtio_device_info);
185e7303c43SKONRAD Frederic }
186e7303c43SKONRAD Frederic 
187e7303c43SKONRAD Frederic type_init(virtio_9p_register_types)
188