This patch implements a very simple virtio transport for 9p in QEMU.  The
kernel side of this is going to change dramatically in the very near future so
this is just a demonstration for the moment.  It requires an external 9p file
server and communicates with it over a TCP port.  In future versions of this
patch, we'll link directly against a 9p file server library and expose the
ability to expose filesystems directly from the QEMU command line.

Signed-off-by: Anthony Liguori <[EMAIL PROTECTED]>

diff --git a/qemu/Makefile.target b/qemu/Makefile.target
index 49c0fc7..fedf1e0 100644
--- a/qemu/Makefile.target
+++ b/qemu/Makefile.target
@@ -449,7 +449,7 @@ VL_OBJS += rtl8139.o
 VL_OBJS+= hypercall.o
 
 # virtio devices
-VL_OBJS += virtio.o virtio-blk.o
+VL_OBJS += virtio.o virtio-blk.o virtio-9p.o
 
 ifeq ($(TARGET_BASE_ARCH), i386)
 # Hardware support
diff --git a/qemu/hw/pc.c b/qemu/hw/pc.c
index c7483e8..fa0346b 100644
--- a/qemu/hw/pc.c
+++ b/qemu/hw/pc.c
@@ -951,6 +951,9 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, 
int boot_device,
        virtio_blk_init(pci_bus, 0x5002, 0x2258, bs);
     }
 
+    if (1)
+       virtio_9p_init(pci_bus, 0x5002, 0x2258);
+
     if (pci_enabled) {
         pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1, i8259);
     } else {
diff --git a/qemu/hw/virtio-9p.c b/qemu/hw/virtio-9p.c
new file mode 100644
index 0000000..c77b594
--- /dev/null
+++ b/qemu/hw/virtio-9p.c
@@ -0,0 +1,121 @@
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <[EMAIL PROTECTED]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "vl.h"
+#include "qemu_socket.h"
+#include "virtio.h"
+#include <sys/uio.h>
+#include <arpa/inet.h>
+
+/* from Linux's linux/virtio_9p.h */
+
+/* The ID for virtio console */
+#define VIRTIO_ID_9P   9
+/* Maximum number of virtio channels per partition (1 for now) */
+#define MAX_9P_CHAN    1
+
+typedef struct V9fsState
+{
+    VirtIODevice vdev;
+
+    int fd;
+    int listening;
+    VirtQueue *in_vq;
+} V9fsState;
+
+static V9fsState *to_v9fs_state(VirtIODevice *vdev)
+{
+    return (V9fsState *)vdev;
+}
+
+static void virtio_9p_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    V9fsState *s = to_v9fs_state(vdev);
+    VirtQueueElement elem;
+    ssize_t len;
+
+    while ((len = virtqueue_pop(vq, &elem)) != 0) {
+       len = writev(s->fd, elem.out_sg, elem.out_num);
+       if (len == -1 && (errno == EINTR || errno == EAGAIN))
+           continue;
+
+       virtqueue_push(vq, &elem, len);
+       virtio_notify(vdev, vq);
+    }
+}
+
+static void virtio_9p_kick_input(VirtIODevice *vdev, VirtQueue *vq)
+{
+    V9fsState *s = to_v9fs_state(vdev);
+    s->listening = 1;
+}
+
+static int virtio_9p_can_read(void *opaque)
+{
+    V9fsState *s = opaque;
+    return s->listening;
+}
+
+static void virtio_9p_handle_input(void *opaque)
+{
+    V9fsState *s = opaque;
+    VirtQueueElement elem;
+    ssize_t len;
+
+    len = virtqueue_pop(s->in_vq, &elem);
+    if (!len) {
+       /* stop listening until more queue space frees up */
+       s->listening = 0;
+       return;
+    }
+
+again:
+    len = readv(s->fd, elem.in_sg, elem.in_num);
+    if (len == -1 && (errno == EINTR || errno == EAGAIN))
+       goto again;
+
+    virtqueue_push(s->in_vq, &elem, len);
+    virtio_notify(&s->vdev, s->in_vq);
+}
+
+VirtIODevice *virtio_9p_init(PCIBus *bus, uint16_t vendor, uint16_t device)
+{
+    V9fsState *s;
+    struct sockaddr_in addr;
+    struct in_addr in;
+
+    s = (V9fsState *)virtio_init_pci(bus, "virtio-9p", vendor, device,
+                                    vendor, VIRTIO_ID_9P,
+                                    0, sizeof(V9fsState));
+
+    s->fd = socket(PF_INET, SOCK_STREAM, 0);
+    if (s->fd == -1)
+       exit(1);
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(1025);
+    inet_aton("127.0.0.1", &in);
+    memcpy(&addr.sin_addr, &in, sizeof(in));
+
+    if (connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
+       exit(2);
+
+    s->listening = 0; /* don't start listening until the queue is inited */
+
+    s->in_vq = virtio_add_queue(&s->vdev, virtio_9p_kick_input);
+    virtio_add_queue(&s->vdev, virtio_9p_handle_output);
+
+    qemu_set_fd_handler2(s->fd, virtio_9p_can_read, virtio_9p_handle_input,
+                        NULL, s);
+
+    return &s->vdev;
+}
diff --git a/qemu/vl.h b/qemu/vl.h
index 249ede2..7b5cc8d 100644
--- a/qemu/vl.h
+++ b/qemu/vl.h
@@ -1399,6 +1399,8 @@ typedef struct VirtIODevice VirtIODevice;
 VirtIODevice *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device,
                              BlockDriverState *bs);
 
+VirtIODevice *virtio_9p_init(PCIBus *bus, uint16_t vendor, uint16_t device);
+
 /* buf = NULL means polling */
 typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out,
                               const uint8_t *buf, int len);

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to