Patchwork [-V3,14/32] virtio-9p: Add multiple mount point support

login
register
mail settings
Submitter Aneesh Kumar K.V
Date March 25, 2010, 4:43 p.m.
Message ID <1269535420-31206-15-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/48565/
State New
Headers show

Comments

Aneesh Kumar K.V - March 25, 2010, 4:43 p.m.
This patch add a mount tag name in 9p config space. This tag should
uniquely identify the mount point and should be used in the mount
command as the device name

Qemu command line for specifying 9p share directory now becomes
-device virtio-9p-pci,share_path=/mnt/,mount_tag=v_mnt
-device virtio-9p-pci,share_path=/tmp/,mount_tag=v_tmp

NOTE: We now limit tag name to 32 characters because of
virtio config space limitation.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
 hw/9p.h              |   26 ++++++
 hw/virtio-9p-local.c |  101 ++++++++++++-------------
 hw/virtio-9p.c       |  206 ++++++++++++++++++++++++-------------------------
 hw/virtio-9p.h       |  141 ++++++++++++++++++++++++++++-------
 hw/virtio-pci.c      |    8 +-
 hw/virtio.h          |    3 +-
 6 files changed, 296 insertions(+), 189 deletions(-)
 create mode 100644 hw/9p.h

Patch

diff --git a/hw/9p.h b/hw/9p.h
new file mode 100644
index 0000000..f0ff45b
--- /dev/null
+++ b/hw/9p.h
@@ -0,0 +1,26 @@ 
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_9P_H
+#define QEMU_9P_H
+
+#include <stdbool.h>
+
+typedef struct V9fsConf
+{
+    char *share_path;
+    /* tag name for the device */
+    char *tag;
+} V9fsConf;
+
+#endif
diff --git a/hw/virtio-9p-local.c b/hw/virtio-9p-local.c
index dca6175..4dd6b22 100644
--- a/hw/virtio-9p-local.c
+++ b/hw/virtio-9p-local.c
@@ -22,22 +22,20 @@ 
 #include <sys/socket.h>
 #include <sys/un.h>
 
-static const char *base_path;
-
-static const char *rpath(const char *path)
+static const char *rpath(V9fsState *s, const char *path)
 {
     /* FIXME: so wrong... */
     static char buffer[4096];
-    snprintf(buffer, sizeof(buffer), "%s/%s", base_path, path);
+    snprintf(buffer, sizeof(buffer), "%s/%s", s->fs_root, path);
     return buffer;
 }
 
-static int local_lstat(void *opaque, const char *path, struct stat *stbuf)
+static int local_lstat(V9fsState *s, const char *path, struct stat *stbuf)
 {
-    return lstat(rpath(path), stbuf);
+    return lstat(rpath(s, path), stbuf);
 }
 
-static int local_setuid(void *opaque, uid_t uid)
+static int local_setuid(V9fsState *s, uid_t uid)
 {
     struct passwd *pw;
     gid_t groups[33];
@@ -72,86 +70,86 @@  static int local_setuid(void *opaque, uid_t uid)
     return 0;
 }
 
-static ssize_t local_readlink(void *opaque, const char *path,
-                                char *buf, size_t bufsz)
+static ssize_t local_readlink(V9fsState *s, const char *path,
+			      char *buf, size_t bufsz)
 {
-    return readlink(rpath(path), buf, bufsz);
+    return readlink(rpath(s, path), buf, bufsz);
 }
 
-static int local_close(void *opaque, int fd)
+static int local_close(V9fsState *s, int fd)
 {
     return close(fd);
 }
 
-static int local_closedir(void *opaque, DIR *dir)
+static int local_closedir(V9fsState *s, DIR *dir)
 {
     return closedir(dir);
 }
 
-static int local_open(void *opaque, const char *path, int flags)
+static int local_open(V9fsState *s, const char *path, int flags)
 {
-    return open(rpath(path), flags);
+    return open(rpath(s, path), flags);
 }
 
-static DIR *local_opendir(void *opaque, const char *path)
+static DIR *local_opendir(V9fsState *s, const char *path)
 {
-    return opendir(rpath(path));
+    return opendir(rpath(s, path));
 }
 
-static void local_rewinddir(void *opaque, DIR *dir)
+static void local_rewinddir(V9fsState *s, DIR *dir)
 {
     return rewinddir(dir);
 }
 
-static off_t local_telldir(void *opaque, DIR *dir)
+static off_t local_telldir(V9fsState *s, DIR *dir)
 {
     return telldir(dir);
 }
 
-static struct dirent *local_readdir(void *opaque, DIR *dir)
+static struct dirent *local_readdir(V9fsState *s, DIR *dir)
 {
     return readdir(dir);
 }
 
-static void local_seekdir(void *opaque, DIR *dir, off_t off)
+static void local_seekdir(V9fsState *s, DIR *dir, off_t off)
 {
     return seekdir(dir, off);
 }
 
-static ssize_t local_readv(void *opaque, int fd, const struct iovec *iov,
+static ssize_t local_readv(V9fsState *s, int fd, const struct iovec *iov,
 			   int iovcnt)
 {
     return readv(fd, iov, iovcnt);
 }
 
-static off_t local_lseek(void *opaque, int fd, off_t offset, int whence)
+static off_t local_lseek(V9fsState *s, int fd, off_t offset, int whence)
 {
     return lseek(fd, offset, whence);
 }
 
-static ssize_t local_writev(void *opaque, int fd, const struct iovec *iov,
+static ssize_t local_writev(V9fsState *s, int fd, const struct iovec *iov,
 			    int iovcnt)
 {
     return writev(fd, iov, iovcnt);
 }
 
-static int local_chmod(void *opaque, const char *path, mode_t mode)
+static int local_chmod(V9fsState *s, const char *path, mode_t mode)
 {
-    return chmod(rpath(path), mode);
+    return chmod(rpath(s, path), mode);
 }
 
-static int local_mknod(void *opaque, const char *path, mode_t mode, dev_t dev)
+static int local_mknod(V9fsState *s, const char *path, mode_t mode, dev_t dev)
 {
-    return mknod(rpath(path), mode, dev);
+    return mknod(rpath(s, path), mode, dev);
 }
 
-static int local_mksock(void *opaque, const char *path)
+static int local_mksock(V9fsState *s2, const char *path)
 {
     struct sockaddr_un addr;
     int s;
 
     addr.sun_family = AF_UNIX;
-    snprintf(addr.sun_path, 108, "%s", rpath(path));
+    snprintf(addr.sun_path, 108, "%s", rpath(s2, path));
 
     s = socket(PF_UNIX, SOCK_STREAM, 0);
     if (s == -1)
@@ -166,36 +164,36 @@  static int local_mksock(void *opaque, const char *path)
     return 0;
 }
 
-static int local_mkdir(void *opaque, const char *path, mode_t mode)
+static int local_mkdir(V9fsState *s, const char *path, mode_t mode)
 {
-    return mkdir(rpath(path), mode);
+    return mkdir(rpath(s, path), mode);
 }
 
-static int local_fstat(void *opaque, int fd, struct stat *stbuf)
+static int local_fstat(V9fsState *s, int fd, struct stat *stbuf)
 {
     return fstat(fd, stbuf);
 }
 
-static int local_open2(void *opaque, const char *path, int flags, mode_t mode)
+static int local_open2(V9fsState *s, const char *path, int flags, mode_t mode)
 {
-    return open(rpath(path), flags, mode);
+    return open(rpath(s, path), flags, mode);
 }
 
-static int local_symlink(void *opaque, const char *oldpath,
+static int local_symlink(V9fsState *s, const char *oldpath,
 			 const char *newpath)
 {
-    return symlink(oldpath, rpath(newpath));
+    return symlink(oldpath, rpath(s, newpath));
 }
 
-static int local_link(void *opaque, const char *oldpath, const char *newpath)
+static int local_link(V9fsState *s, const char *oldpath, const char *newpath)
 {
-    char *tmp = qemu_strdup(rpath(oldpath));
+    char *tmp = qemu_strdup(rpath(s, oldpath));
     int err, serrno = 0;
 
     if (tmp == NULL)
 	return -ENOMEM;
 
-    err = link(tmp, rpath(newpath));
+    err = link(tmp, rpath(s, newpath));
     if (err == -1)
 	serrno = errno;
 
@@ -207,22 +205,22 @@  static int local_link(void *opaque, const char *oldpath, const char *newpath)
     return err;
 }
 
-static int local_truncate(void *opaque, const char *path, off_t size)
+static int local_truncate(V9fsState *s, const char *path, off_t size)
 {
-    return truncate(rpath(path), size);
+    return truncate(rpath(s, path), size);
 }
 
-static int local_rename(void *opaque, const char *oldpath,
+static int local_rename(V9fsState *s, const char *oldpath,
 			const char *newpath)
 {
     char *tmp;
     int err;
 
-    tmp = qemu_strdup(rpath(oldpath));
+    tmp = qemu_strdup(rpath(s, oldpath));
     if (tmp == NULL)
 	return -1;
 
-    err = rename(tmp, rpath(newpath));
+    err = rename(tmp, rpath(s, newpath));
     if (err == -1) {
 	int serrno = errno;
 	qemu_free(tmp);
@@ -234,20 +232,20 @@  static int local_rename(void *opaque, const char *oldpath,
 
 }
 
-static int local_chown(void *opaque, const char *path, uid_t uid, gid_t gid)
+static int local_chown(V9fsState *s, const char *path, uid_t uid, gid_t gid)
 {
-    return chown(rpath(path), uid, gid);
+    return chown(rpath(s, path), uid, gid);
 }
 
-static int local_utime(void *opaque, const char *path,
+static int local_utime(V9fsState *s, const char *path,
 		       const struct utimbuf *buf)
 {
-    return utime(rpath(path), buf);
+    return utime(rpath(s, path), buf);
 }
 
-static int local_remove(void *opaque, const char *path)
+static int local_remove(V9fsState *s, const char *path)
 {
-    return remove(rpath(path));
+    return remove(rpath(s, path));
 }
 
 
@@ -283,6 +281,5 @@  static V9fsPosixFileOperations ops = {
 
 V9fsPosixFileOperations *virtio_9p_init_local(const char *path)
 {
-    base_path = path;
-    return &ops;
+return &ops;
 }
diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c
index 1dbb982..e095916 100644
--- a/hw/virtio-9p.c
+++ b/hw/virtio-9p.c
@@ -15,78 +15,8 @@ 
 #include "pc.h"
 #include "qemu_socket.h"
 #include "virtio-9p.h"
-
 #include <assert.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
-
-#define MAX_REQ		128
-
-#define BUG_ON(cond) assert(!(cond))
-
-typedef struct V9fsFidState V9fsFidState;
-
-typedef struct V9fsString
-{
-    int16_t size;
-    char *data;
-} V9fsString;
-
-typedef struct V9fsQID
-{
-    int8_t type;
-    int32_t version;
-    int64_t path;
-} V9fsQID;
-
-typedef struct V9fsStat
-{
-    int16_t size;
-    int16_t type;
-    int32_t dev;
-    V9fsQID qid;
-    int32_t mode;
-    int32_t atime;
-    int32_t mtime;
-    int64_t length;
-    V9fsString name;
-    V9fsString uid;
-    V9fsString gid;
-    V9fsString muid;
-    /* 9p2000.u */
-    V9fsString extension;
-    int32_t n_uid;
-    int32_t n_gid;
-    int32_t n_muid;
-} V9fsStat;
-
-struct V9fsFidState
-{
-    int32_t fid;
-    V9fsString path;
-    int fd;
-    DIR *dir;
-    uid_t uid;
-    V9fsFidState *next;
-};
-
-typedef struct V9fsState
-{
-    VirtIODevice vdev;
-    VirtQueue *vq;
-    V9fsPDU pdus[MAX_REQ];
-    V9fsPDU *free_pdu;
-    V9fsFidState *fid_list;
-    V9fsPosixFileOperations *ops;
-    char *root;
-    uid_t uid;
-} V9fsState;
-
 int dotu = 1;
 int debug_9p_pdu = 1;
 
@@ -94,12 +24,12 @@  extern void pprint_pdu(V9fsPDU *pdu);
 
 static int posix_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
 {
-    return s->ops->lstat(s->ops->opaque, path->data, stbuf);
+    return s->ops->lstat(s, path->data, stbuf);
 }
 
 static int posix_setuid(V9fsState *s, uid_t uid)
 {
-    return s->ops->setuid(s->ops->opaque, uid);
+    return s->ops->setuid(s, uid);
 }
 
 static ssize_t posix_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
@@ -108,7 +38,7 @@  static ssize_t posix_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
 
     buf->data = qemu_malloc(1024);
 
-    len = s->ops->readlink(s->ops->opaque, path->data, buf->data, 1024 - 1);
+    len = s->ops->readlink(s, path->data, buf->data, 1024 - 1);
     if (len > -1) {
         buf->size = len;
         buf->data[len] = 0;
@@ -119,127 +49,127 @@  static ssize_t posix_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
 
 static int posix_close(V9fsState *s, int fd)
 {
-    return s->ops->close(s->ops->opaque, fd);
+    return s->ops->close(s, fd);
 }
 
 static int posix_closedir(V9fsState *s, DIR *dir)
 {
-    return s->ops->closedir(s->ops->opaque, dir);
+    return s->ops->closedir(s, dir);
 }
 
 static int posix_open(V9fsState *s, V9fsString *path, int flags)
 {
-    return s->ops->open(s->ops->opaque, path->data, flags);
+    return s->ops->open(s, path->data, flags);
 }
 
 static DIR *posix_opendir(V9fsState *s, V9fsString *path)
 {
-    return s->ops->opendir(s->ops->opaque, path->data);
+    return s->ops->opendir(s, path->data);
 }
 
 static void posix_rewinddir(V9fsState *s, DIR *dir)
 {
-    return s->ops->rewinddir(s->ops->opaque, dir);
+    return s->ops->rewinddir(s, dir);
 }
 
 static off_t posix_telldir(V9fsState *s, DIR *dir)
 {
-    return s->ops->telldir(s->ops->opaque, dir);
+    return s->ops->telldir(s, dir);
 }
 
 static struct dirent *posix_readdir(V9fsState *s, DIR *dir)
 {
-    return s->ops->readdir(s->ops->opaque, dir);
+    return s->ops->readdir(s, dir);
 }
 
 static void posix_seekdir(V9fsState *s, DIR *dir, off_t off)
 {
-    return s->ops->seekdir(s->ops->opaque, dir, off);
+    return s->ops->seekdir(s, dir, off);
 }
 
 static int posix_readv(V9fsState *s, int fd, const struct iovec *iov,
 		       int iovcnt)
 {
-    return s->ops->readv(s->ops->opaque, fd, iov, iovcnt);
+    return s->ops->readv(s, fd, iov, iovcnt);
 }
 
 static off_t posix_lseek(V9fsState *s, int fd, off_t offset, int whence)
 {
-    return s->ops->lseek(s->ops->opaque, fd, offset, whence);
+    return s->ops->lseek(s, fd, offset, whence);
 }
 
 static int posix_writev(V9fsState *s, int fd, const struct iovec *iov,
                        int iovcnt)
 {
-    return s->ops->writev(s->ops->opaque, fd, iov, iovcnt);
+    return s->ops->writev(s, fd, iov, iovcnt);
 }
 
 static int posix_chmod(V9fsState *s, V9fsString *path, mode_t mode)
 {
-    return s->ops->chmod(s->ops->opaque, path->data, mode);
+    return s->ops->chmod(s, path->data, mode);
 }
 
 static int posix_mknod(V9fsState *s, V9fsString *path, mode_t mode, dev_t dev)
 {
-    return s->ops->mknod(s->ops->opaque, path->data, mode, dev);
+    return s->ops->mknod(s, path->data, mode, dev);
 }
 
 static int posix_mksock(V9fsState *s, V9fsString *path)
 {
-    return s->ops->mksock(s->ops->opaque, path->data);
+    return s->ops->mksock(s, path->data);
 }
 
 static int posix_mkdir(V9fsState *s, V9fsString *path, mode_t mode)
 {
-    return s->ops->mkdir(s->ops->opaque, path->data, mode);
+    return s->ops->mkdir(s, path->data, mode);
 }
 
 static int posix_fstat(V9fsState *s, int fd, struct stat *stbuf)
 {
-    return s->ops->fstat(s->ops->opaque, fd, stbuf);
+    return s->ops->fstat(s, fd, stbuf);
 }
 
 static int posix_open2(V9fsState *s, V9fsString *path, int flags, mode_t mode)
 {
-    return s->ops->open2(s->ops->opaque, path->data, flags, mode);
+    return s->ops->open2(s, path->data, flags, mode);
 }
 
 static int posix_symlink(V9fsState *s, V9fsString *oldpath,
 			 V9fsString *newpath)
 {
-    return s->ops->symlink(s->ops->opaque, oldpath->data, newpath->data);
+    return s->ops->symlink(s, oldpath->data, newpath->data);
 }
 
 static int posix_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
 {
-    return s->ops->link(s->ops->opaque, oldpath->data, newpath->data);
+    return s->ops->link(s, oldpath->data, newpath->data);
 }
 
 static int posix_truncate(V9fsState *s, V9fsString *path, off_t size)
 {
-    return s->ops->truncate(s->ops->opaque, path->data, size);
+    return s->ops->truncate(s, path->data, size);
 }
 
 static int posix_rename(V9fsState *s, V9fsString *oldpath,
 			V9fsString *newpath)
 {
-    return s->ops->rename(s->ops->opaque, oldpath->data, newpath->data);
+    return s->ops->rename(s, oldpath->data, newpath->data);
 }
 
 static int posix_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
 {
-    return s->ops->chown(s->ops->opaque, path->data, uid, gid);
+    return s->ops->chown(s, path->data, uid, gid);
 }
 
 static int posix_utime(V9fsState *s, V9fsString *path,
 		       const struct utimbuf *buf)
 {
-    return s->ops->utime(s->ops->opaque, path->data, buf);
+    return s->ops->utime(s, path->data, buf);
 }
 
 static int posix_remove(V9fsState *s, V9fsString *path)
 {
-    return s->ops->remove(s->ops->opaque, path->data);
+    return s->ops->remove(s, path->data);
 }
 
 static void v9fs_string_init(V9fsString *str)
@@ -785,7 +715,7 @@  static void v9fs_attach(V9fsState *s, V9fsPDU *pdu)
 
     fidp->uid = n_uname;
 
-    v9fs_string_sprintf(&fidp->path, "%s", s->root);
+    v9fs_string_sprintf(&fidp->path, "%s", "/");
     fid_to_qid(s, fidp, &qid);
 
     offset += pdu_marshal(pdu, offset, "Q", &qid);
@@ -2045,17 +1975,58 @@  static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
 
 static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
 {
+    features |= 1 << VIRTIO_9P_MOUNT_TAG;
     return features;
 }
 
-VirtIODevice *virtio_9p_init(DeviceState *dev, const char *path)
+static V9fsState *to_virtio_9p(VirtIODevice *vdev)
+{
+    return (V9fsState *)vdev;
+}
+
+static void virtio_9p_set_config(VirtIODevice *vdev, const uint8_t *config)
+{
+    uint16_t tag_len;
+    struct virtio_9p_config *cfg;
+    V9fsState *s = to_virtio_9p(vdev);
+
+    memcpy(&tag_len, config, sizeof(tag_len));
+    cfg = qemu_mallocz(sizeof(struct virtio_9p_config) + tag_len);
+
+    memcpy(cfg, config, s->config_size);
+    memcpy(&s->tag_len, &cfg->tag_len, sizeof(uint16_t));
+    /* free the old config details */
+    qemu_free(s->tag);
+    s->tag = qemu_malloc(tag_len);
+    memcpy(s->tag, cfg->tag, cfg->tag_len);
+    qemu_free(cfg);
+}
+
+static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
 {
+    struct virtio_9p_config *cfg;
+    V9fsState *s = to_virtio_9p(vdev);
+
+    cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
+			    s->tag_len);
+    memcpy(&cfg->tag_len, &s->tag_len, sizeof(uint16_t));
+    memcpy(cfg->tag, s->tag, s->tag_len);
+    memcpy(config, cfg, s->config_size);
+    qemu_free(cfg);
+}
+
+VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
+ {
     V9fsState *s;
-    int i;
+    int i, len;
+    struct stat stat;
+
 
     s = (V9fsState *)virtio_common_init("virtio-9p",
-                                        VIRTIO_ID_9P,
-                                        0, sizeof(V9fsState));
+                                    VIRTIO_ID_9P,
+                                    sizeof(struct virtio_9p_config)+
+                                    MAX_TAG_LEN,
+                                    sizeof(V9fsState));
 
     /* initialize pdu allocator */
     s->free_pdu = &s->pdus[0];
@@ -2066,12 +2037,37 @@  VirtIODevice *virtio_9p_init(DeviceState *dev, const char *path)
     s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
     BUG_ON(s->vq == NULL);
 
-    s->root = strdup("/");
-    BUG_ON(s->root == NULL);
+    if (!conf->share_path || !conf->tag) {
+	    /* we haven't specified a mount_tag */
+	    fprintf(stderr, "Virtio-9p devices need share_path "
+		    "and mount_tag arguments\n");
+	    exit(1);
+    }
+    if (lstat(conf->share_path, &stat)) {
+	    fprintf(stderr, "share path %s does not exist\n", conf->share_path);
+	    exit(1);
+    } else if (!S_ISDIR(stat.st_mode)) {
+	    fprintf(stderr, "share path %s is not a directory \n", conf->share_path);
+	    exit(1);
+    }
+    s->fs_root = qemu_strdup(conf->share_path);
+    len = strlen(conf->tag);
+    if (len > MAX_TAG_LEN)
+	    len = MAX_TAG_LEN;
+    /* s->tag is non-NULL terminated string */
+    s->tag = qemu_malloc(len);
+    memcpy(s->tag, conf->tag, len);
+    s->tag_len = len;
+    BUG_ON(s->fs_root == NULL);
     s->uid = -1;
 
-    s->ops = virtio_9p_init_local(path);
+    s->ops = virtio_9p_init_local(conf->share_path);
     s->vdev.get_features = virtio_9p_get_features;
+    s->config_size = sizeof(struct virtio_9p_config) +
+			s->tag_len;
+    s->vdev.get_config = virtio_9p_get_config;
+    s->vdev.set_config = virtio_9p_set_config;
+
 
     return &s->vdev;
 }
diff --git a/hw/virtio-9p.h b/hw/virtio-9p.h
index 8e15bf0..3fc88a4 100644
--- a/hw/virtio-9p.h
+++ b/hw/virtio-9p.h
@@ -6,6 +6,10 @@ 
 #include <sys/time.h>
 #include <utime.h>
 
+/* The feature bitmap for virtio 9P */
+/* The mount point is specified in a config variable */
+#define VIRTIO_9P_MOUNT_TAG 0
+
 enum {
     P9_TVERSION = 100,
     P9_RVERSION,
@@ -66,35 +70,118 @@  struct V9fsPDU
     V9fsPDU *next;
 };
 
+/* FIXME
+ * 1) change user needs to set groups and stuff
+ */
+
+/* from Linux's linux/virtio_9p.h */
+
+/* The ID for virtio console */
+#define VIRTIO_ID_9P	9
+#define MAX_REQ		128
+#define MAX_TAG_LEN	32
+
+#define BUG_ON(cond) assert(!(cond))
+
+typedef struct V9fsFidState V9fsFidState;
+
+typedef struct V9fsString
+{
+    int16_t size;
+    char *data;
+} V9fsString;
+
+typedef struct V9fsQID
+{
+    int8_t type;
+    int32_t version;
+    int64_t path;
+} V9fsQID;
+
+typedef struct V9fsStat
+{
+    int16_t size;
+    int16_t type;
+    int32_t dev;
+    V9fsQID qid;
+    int32_t mode;
+    int32_t atime;
+    int32_t mtime;
+    int64_t length;
+    V9fsString name;
+    V9fsString uid;
+    V9fsString gid;
+    V9fsString muid;
+    /* 9p2000.u */
+    V9fsString extension;
+    int32_t n_uid;
+    int32_t n_gid;
+    int32_t n_muid;
+} V9fsStat;
+
+struct V9fsFidState
+{
+    int32_t fid;
+    V9fsString path;
+    int fd;
+    DIR *dir;
+    uid_t uid;
+    V9fsFidState *next;
+};
+
+struct V9fsPosixFileOpertions ;
+typedef struct V9fsState
+{
+    VirtIODevice vdev;
+    VirtQueue *vq;
+    V9fsPDU pdus[MAX_REQ];
+    V9fsPDU *free_pdu;
+    V9fsFidState *fid_list;
+    struct V9fsPosixFileOpertions *ops;
+    char *fs_root;
+    uid_t uid;
+    uint16_t tag_len;
+    uint8_t *tag;
+    size_t config_size;
+} V9fsState;
+
+struct virtio_9p_config
+{
+    /* number of characters in tag */
+    uint16_t tag_len;
+    /* Variable size tag name */
+    uint8_t tag[0];
+} __attribute__((packed));
+
 typedef struct V9fsPosixFileOpertions
 {
-    int (*lstat)(void *, const char *, struct stat *);
-    ssize_t (*readlink)(void *, const char *, char *, size_t);
-    int (*chmod)(void *, const char *, mode_t);
-    int (*chown)(void *, const char *, uid_t, gid_t);
-    int (*mknod)(void *, const char *, mode_t, dev_t);
-    int (*mksock)(void *, const char *);
-    int (*utime)(void *, const char *, const struct utimbuf *);
-    int (*remove)(void *, const char *);
-    int (*symlink)(void *, const char *, const char *);
-    int (*link)(void *, const char *, const char *);
-    int (*setuid)(void *, uid_t);
-    int (*close)(void *, int);
-    int (*closedir)(void *, DIR *);
-    DIR *(*opendir)(void *, const char *);
-    int (*open)(void *, const char *, int);
-    int (*open2)(void *, const char *, int, mode_t);
-    void (*rewinddir)(void *, DIR *);
-    off_t (*telldir)(void *, DIR *);
-    struct dirent *(*readdir)(void *, DIR *);
-    void (*seekdir)(void *, DIR *, off_t);
-    ssize_t (*readv)(void *, int, const struct iovec *, int);
-    ssize_t (*writev)(void *, int, const struct iovec *, int);
-    off_t (*lseek)(void *, int, off_t, int);
-    int (*mkdir)(void *, const char *, mode_t);
-    int (*fstat)(void *, int, struct stat *);
-    int (*rename)(void *, const char *, const char *);
-    int (*truncate)(void *, const char *, off_t);
+    int (*lstat)(V9fsState *, const char *, struct stat *);
+    ssize_t (*readlink)(V9fsState *, const char *, char *, size_t);
+    int (*chmod)(V9fsState *, const char *, mode_t);
+    int (*chown)(V9fsState *, const char *, uid_t, gid_t);
+    int (*mknod)(V9fsState *, const char *, mode_t, dev_t);
+    int (*mksock)(V9fsState *, const char *);
+    int (*utime)(V9fsState *, const char *, const struct utimbuf *);
+    int (*remove)(V9fsState *, const char *);
+    int (*symlink)(V9fsState *, const char *, const char *);
+    int (*link)(V9fsState *, const char *, const char *);
+    int (*setuid)(V9fsState *, uid_t);
+    int (*close)(V9fsState *, int);
+    int (*closedir)(V9fsState *, DIR *);
+    DIR *(*opendir)(V9fsState *, const char *);
+    int (*open)(V9fsState *, const char *, int);
+    int (*open2)(V9fsState *, const char *, int, mode_t);
+    void (*rewinddir)(V9fsState *, DIR *);
+    off_t (*telldir)(V9fsState *, DIR *);
+    struct dirent *(*readdir)(V9fsState *, DIR *);
+    void (*seekdir)(V9fsState *, DIR *, off_t);
+    ssize_t (*readv)(V9fsState *, int, const struct iovec *, int);
+    ssize_t (*writev)(V9fsState *, int, const struct iovec *, int);
+    off_t (*lseek)(V9fsState *, int, off_t, int);
+    int (*mkdir)(V9fsState *, const char *, mode_t);
+    int (*fstat)(V9fsState *, int, struct stat *);
+    int (*rename)(V9fsState *, const char *, const char *);
+    int (*truncate)(V9fsState *, const char *, off_t);
     void *opaque;
 } V9fsPosixFileOperations;
 
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 85879fb..73e7df7 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -86,7 +86,6 @@ 
 #define wmb() do { } while (0)
 
 /* PCI bindings.  */
-
 typedef struct {
     PCIDevice pci_dev;
     VirtIODevice *vdev;
@@ -96,7 +95,7 @@  typedef struct {
     BlockConf block;
     NICConf nic;
     uint32_t host_features;
-    char *share_path;
+    V9fsConf fsconf;
     /* Max. number of ports we can have for a the virtio-serial device */
     uint32_t max_virtserial_ports;
 } VirtIOPCIProxy;
@@ -558,7 +557,7 @@  static int virtio_9p_init_pci(PCIDevice *pci_dev)
     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
     VirtIODevice *vdev;
 
-    vdev = virtio_9p_init(&pci_dev->qdev, proxy->share_path);
+    vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
     virtio_init_pci(proxy, vdev,
 		    PCI_VENDOR_ID_REDHAT_QUMRANET,
 		    0x1009,
@@ -627,7 +626,8 @@  static PCIDeviceInfo virtio_info[] = {
         .init      = virtio_9p_init_pci,
         .qdev.props = (Property[]) {
             DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
-            DEFINE_PROP_STRING("share_path", VirtIOPCIProxy, share_path),
+            DEFINE_PROP_STRING("share_path", VirtIOPCIProxy, fsconf.share_path),
+            DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
             DEFINE_PROP_END_OF_LIST(),
         },
     },{
diff --git a/hw/virtio.h b/hw/virtio.h
index 4032a96..c11a380 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -19,6 +19,7 @@ 
 #include "qdev.h"
 #include "sysemu.h"
 #include "block_int.h"
+#include "9p.h"
 
 /* from Linux's linux/virtio_config.h */
 
@@ -174,7 +175,7 @@  VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf);
 VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf);
 VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports);
 VirtIODevice *virtio_balloon_init(DeviceState *dev);
-VirtIODevice *virtio_9p_init(DeviceState *dev, const char *path);
+VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
 
 void virtio_net_exit(VirtIODevice *vdev);