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