diff mbox

[2/2] tools/kvm/9p: Add support for multiple 9p export dirs

Message ID 1308334282-11865-2-git-send-email-aneesh.kumar@linux.vnet.ibm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Aneesh Kumar K.V June 17, 2011, 6:11 p.m. UTC
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
 tools/kvm/include/kvm/virtio-9p.h |    2 +-
 tools/kvm/kvm-run.c               |   37 +++--
 tools/kvm/virtio/9p.c             |  357 +++++++++++++++++++++---------------
 3 files changed, 234 insertions(+), 162 deletions(-)

Comments

Sasha Levin June 17, 2011, 8:06 p.m. UTC | #1
On Fri, 2011-06-17 at 23:41 +0530, Aneesh Kumar K.V wrote:
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> ---
>  tools/kvm/include/kvm/virtio-9p.h |    2 +-
>  tools/kvm/kvm-run.c               |   37 +++--
>  tools/kvm/virtio/9p.c             |  357 +++++++++++++++++++++---------------
>  3 files changed, 234 insertions(+), 162 deletions(-)

Looks great!

	Acked-by: Sasha Levin <levinsasha928@gmail.com>
diff mbox

Patch

diff --git a/tools/kvm/include/kvm/virtio-9p.h b/tools/kvm/include/kvm/virtio-9p.h
index 9052830..d99bf96 100644
--- a/tools/kvm/include/kvm/virtio-9p.h
+++ b/tools/kvm/include/kvm/virtio-9p.h
@@ -3,6 +3,6 @@ 
 
 struct kvm;
 
-void virtio_9p__init(struct kvm *kvm, const char *root);
+void virtio_9p__init(struct kvm *kvm, const char *root, const char *tag_name);
 
 #endif
diff --git a/tools/kvm/kvm-run.c b/tools/kvm/kvm-run.c
index 6ad55aa..60fc07b 100644
--- a/tools/kvm/kvm-run.c
+++ b/tools/kvm/kvm-run.c
@@ -69,7 +69,6 @@  static const char *network;
 static const char *host_ip_addr;
 static const char *guest_mac;
 static const char *script;
-static const char *virtio_9p_dir;
 static bool single_step;
 static bool readonly_image[MAX_DISK_IMAGES];
 static bool vnc;
@@ -108,6 +107,29 @@  static int img_name_parser(const struct option *opt, const char *arg, int unset)
 	return 0;
 }
 
+static int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, int unset)
+{
+	char *tag_name;
+	char tmp[PATH_MAX];
+
+	/*
+	 * 9p dir can be of the form dirname,tag_name or
+	 * just dirname. In the later case we use the
+	 * default tag name
+	 */
+	tag_name = strstr(arg, ",");
+	if (tag_name) {
+		*tag_name = '\0';
+		tag_name++;
+	}
+	if (realpath(arg, tmp))
+		virtio_9p__init(kvm, tmp, tag_name);
+	else
+		die("Failed resolving 9p path");
+	return 0;
+}
+
+
 static const struct option options[] = {
 	OPT_GROUP("Basic options:"),
 	OPT_INTEGER('c', "cpus", &nrcpus, "Number of CPUs"),
@@ -118,8 +140,8 @@  static const struct option options[] = {
 	OPT_INCR('\0', "rng", &virtio_rng,
 			"Enable virtio Random Number Generator"),
 	OPT_STRING('\0', "kvm-dev", &kvm_dev, "kvm-dev", "KVM device file"),
-	OPT_STRING('\0', "virtio-9p", &virtio_9p_dir, "root dir",
-			"Enable 9p over virtio"),
+	OPT_CALLBACK('\0', "virtio-9p", NULL, "dirname,tag_name",
+		     "Enable 9p over virtio", virtio_9p_rootdir_parser),
 	OPT_BOOLEAN('\0', "vnc", &vnc, "Enable VNC framebuffer"),
 	OPT_BOOLEAN('\0', "sdl", &sdl, "Enable SDL framebuffer"),
 
@@ -520,15 +542,6 @@  int kvm_cmd_run(int argc, const char **argv, const char *prefix)
 	if (!script)
 		script = DEFAULT_SCRIPT;
 
-	if (virtio_9p_dir) {
-		char tmp[PATH_MAX];
-
-		if (realpath(virtio_9p_dir, tmp))
-			virtio_9p__init(kvm, tmp);
-		else
-			die("Failed resolving 9p path");
-	}
-
 	symbol__init(vmlinux_filename);
 
 	term_init();
diff --git a/tools/kvm/virtio/9p.c b/tools/kvm/virtio/9p.c
index 918bb81..b55d088 100644
--- a/tools/kvm/virtio/9p.c
+++ b/tools/kvm/virtio/9p.c
@@ -21,10 +21,12 @@ 
 
 #define NUM_VIRT_QUEUES		1
 #define VIRTIO_P9_QUEUE_SIZE	128
-#define	VIRTIO_P9_TAG		"kvm_9p"
+#define	VIRTIO_P9_DEFAULT_TAG	"kvm_9p"
 #define VIRTIO_P9_HDR_LEN	(sizeof(u32)+sizeof(u8)+sizeof(u16))
 #define VIRTIO_P9_MAX_FID	128
 #define VIRTIO_P9_VERSION	"9P2000"
+#define MAX_TAG_LEN		32
+
 
 struct p9_msg {
 	u32			size;
@@ -42,14 +44,10 @@  struct p9_fid {
 	int			fd;
 };
 
-static struct pci_device_header virtio_p9_pci_device = {
-	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
-	.device_id		= PCI_DEVICE_ID_VIRTIO_P9,
-	.header_type		= PCI_HEADER_TYPE_NORMAL,
-	.revision_id		= 0,
-	.class			= 0x010000,
-	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
-	.subsys_id		= VIRTIO_ID_9P,
+struct p9_dev_job {
+	struct virt_queue		*vq;
+	struct p9_dev			*p9dev;
+	void				*job_id;
 };
 
 struct p9_dev {
@@ -63,25 +61,26 @@  struct p9_dev {
 	/* virtio queue */
 	u16			queue_selector;
 	struct virt_queue	vqs[NUM_VIRT_QUEUES];
-	void			*jobs[NUM_VIRT_QUEUES];
-
+	struct p9_dev_job	jobs[NUM_VIRT_QUEUES];
 	struct p9_fid		fids[VIRTIO_P9_MAX_FID];
 	char			root_dir[PATH_MAX];
+	struct pci_device_header pci_hdr;
 };
 
-static struct p9_dev p9dev;
-
 /* Warning: Immediately use value returned from this function */
-static const char *rel_to_abs(const char *path, char *abs_path)
+static const char *rel_to_abs(struct p9_dev *p9dev,
+			      const char *path, char *abs_path)
 {
-	sprintf(abs_path, "%s/%s", p9dev.root_dir, path);
+	sprintf(abs_path, "%s/%s", p9dev->root_dir, path);
 
 	return abs_path;
 }
 
-static bool virtio_p9_dev_in(void *data, unsigned long offset, int size, u32 count)
+static bool virtio_p9_dev_in(struct p9_dev *p9dev, void *data,
+			     unsigned long offset,
+			     int size, u32 count)
 {
-	u8 *config_space = (u8 *) p9dev.config;
+	u8 *config_space = (u8 *) p9dev->config;
 
 	if (size != 1 || count != 1)
 		return false;
@@ -91,16 +90,19 @@  static bool virtio_p9_dev_in(void *data, unsigned long offset, int size, u32 cou
 	return true;
 }
 
-static bool virtio_p9_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_p9_pci_io_in(struct ioport *ioport, struct kvm *kvm,
+				u16 port, void *data, int size, u32 count)
 {
-	unsigned long offset;
 	bool ret = true;
+	unsigned long offset;
+	struct p9_dev *p9dev = ioport->priv;
 
-	offset = port - p9dev.base_addr;
+
+	offset = port - p9dev->base_addr;
 
 	switch (offset) {
 	case VIRTIO_PCI_HOST_FEATURES:
-		ioport__write32(data, p9dev.features);
+		ioport__write32(data, p9dev->features);
 		ret = true;
 		break;
 	case VIRTIO_PCI_GUEST_FEATURES:
@@ -109,21 +111,21 @@  static bool virtio_p9_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port
 		ret = false;
 		break;
 	case VIRTIO_PCI_QUEUE_PFN:
-		ioport__write32(data, p9dev.vqs[p9dev.queue_selector].pfn);
+		ioport__write32(data, p9dev->vqs[p9dev->queue_selector].pfn);
 		break;
 	case VIRTIO_PCI_QUEUE_NUM:
 		ioport__write16(data, VIRTIO_P9_QUEUE_SIZE);
 		break;
 	case VIRTIO_PCI_STATUS:
-		ioport__write8(data, p9dev.status);
+		ioport__write8(data, p9dev->status);
 		break;
 	case VIRTIO_PCI_ISR:
-		ioport__write8(data, p9dev.isr);
-		kvm__irq_line(kvm, virtio_p9_pci_device.irq_line, VIRTIO_IRQ_LOW);
-		p9dev.isr = VIRTIO_IRQ_LOW;
+		ioport__write8(data, p9dev->isr);
+		kvm__irq_line(kvm, p9dev->pci_hdr.irq_line, VIRTIO_IRQ_LOW);
+		p9dev->isr = VIRTIO_IRQ_LOW;
 		break;
 	default:
-		ret = virtio_p9_dev_in(data, offset, size, count);
+		ret = virtio_p9_dev_in(p9dev, data, offset, size, count);
 		break;
 	};
 
@@ -161,15 +163,15 @@  static void st2qid(struct stat *st, struct p9_qid *qid)
 		qid->type	|= P9_QTDIR;
 }
 
-static void close_fid(u32 fid)
+static void close_fid(struct p9_dev *p9dev, u32 fid)
 {
-	if (p9dev.fids[fid].fd > 0) {
-		close(p9dev.fids[fid].fd);
-		p9dev.fids[fid].fd = -1;
+	if (p9dev->fids[fid].fd > 0) {
+		close(p9dev->fids[fid].fd);
+		p9dev->fids[fid].fd = -1;
 	}
-	if (p9dev.fids[fid].dir) {
-		closedir(p9dev.fids[fid].dir);
-		p9dev.fids[fid].dir = NULL;
+	if (p9dev->fids[fid].dir) {
+		closedir(p9dev->fids[fid].dir);
+		p9dev->fids[fid].dir = NULL;
 	}
 }
 
@@ -182,7 +184,9 @@  static void set_p9msg_hdr(struct p9_msg *msg, u32 size, u8 cmd, u16 tag)
 	};
 }
 
-static bool virtio_p9_version(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
+static bool virtio_p9_version(struct p9_dev *p9dev, struct p9_msg *msg,
+			      u32 len, struct iovec *iov,
+			      int outiovcnt, int iniovcnt, u32 *outlen)
 {
 	struct p9_msg *outmsg = iov[0].iov_base;
 	struct p9_rversion *rversion = (struct p9_rversion *)outmsg->msg;
@@ -191,18 +195,21 @@  static bool virtio_p9_version(struct p9_msg *msg, u32 len, struct iovec *iov, u3
 	rversion->version.len	= strlen(VIRTIO_P9_VERSION);
 	memcpy(&rversion->version.str, VIRTIO_P9_VERSION, rversion->version.len);
 
-	*outlen = VIRTIO_P9_HDR_LEN + rversion->version.len + sizeof(u16) + sizeof(u32);
+	*outlen = VIRTIO_P9_HDR_LEN +
+		rversion->version.len + sizeof(u16) + sizeof(u32);
 	set_p9msg_hdr(outmsg, *outlen, P9_RVERSION, msg->tag);
 
 	return true;
 }
 
-static bool virtio_p9_clunk(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
+static bool virtio_p9_clunk(struct p9_dev *p9dev, struct p9_msg *msg,
+			    u32 len, struct iovec *iov,
+			    int outiovcnt, int iniovcnt, u32 *outlen)
 {
 	struct p9_msg *outmsg = iov[0].iov_base;
 	struct p9_tclunk *tclunk = (struct p9_tclunk *)msg->msg;
 
-	close_fid(tclunk->fid);
+	close_fid(p9dev, tclunk->fid);
 
 	*outlen = VIRTIO_P9_HDR_LEN;
 	set_p9msg_hdr(outmsg, *outlen, P9_RCLUNK, msg->tag);
@@ -210,12 +217,14 @@  static bool virtio_p9_clunk(struct p9_msg *msg, u32 len, struct iovec *iov, u32
 	return true;
 }
 
-static bool virtio_p9_open(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
+static bool virtio_p9_open(struct p9_dev *p9dev, struct p9_msg *msg,
+			   u32 len, struct iovec *iov,
+			   int outiovcnt, int iniovcnt, u32 *outlen)
 {
 	struct p9_msg *outmsg	= iov[0].iov_base;
 	struct p9_topen *topen	= (struct p9_topen *)msg->msg;
 	struct p9_ropen *ropen	= (struct p9_ropen *)outmsg->msg;
-	struct p9_fid *new_fid	= &p9dev.fids[topen->fid];
+	struct p9_fid *new_fid	= &p9dev->fids[topen->fid];
 	struct stat st;
 
 	if (stat(new_fid->abs_path, &st) < 0)
@@ -235,12 +244,14 @@  static bool virtio_p9_open(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *
 	return true;
 }
 
-static bool virtio_p9_create(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
+static bool virtio_p9_create(struct p9_dev *p9dev, struct p9_msg *msg,
+			     u32 len, struct iovec *iov,
+			     int outiovcnt, int iniovcnt, u32 *outlen)
 {
 	struct p9_msg *outmsg		= iov[0].iov_base;
 	struct p9_tcreate *tcreate	= (struct p9_tcreate *)msg->msg;
 	struct p9_rcreate *rcreate	= (struct p9_rcreate *)outmsg->msg;
-	struct p9_fid *fid		= &p9dev.fids[tcreate->fid];
+	struct p9_fid *fid		= &p9dev->fids[tcreate->fid];
 	struct stat st;
 	u8 mode;
 	u32 perm;
@@ -253,7 +264,7 @@  static bool virtio_p9_create(struct p9_msg *msg, u32 len, struct iovec *iov, u32
 
 	sprintf(fid->path, "%s/%.*s", fid->path, tcreate->name.len, (char *)&tcreate->name.str);
 
-	close_fid(tcreate->fid);
+	close_fid(p9dev, tcreate->fid);
 
 	if (perm & P9_DMDIR) {
 		mkdir(fid->abs_path, perm & 0xFFFF);
@@ -274,18 +285,20 @@  static bool virtio_p9_create(struct p9_msg *msg, u32 len, struct iovec *iov, u32
 	return true;
 }
 
-static bool virtio_p9_walk(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
+static bool virtio_p9_walk(struct p9_dev *p9dev, struct p9_msg *msg,
+			   u32 len, struct iovec *iov,
+			   int outiovcnt, int iniovcnt, u32 *outlen)
 {
 	struct p9_msg *outmsg	= iov[0].iov_base;
 	struct p9_twalk *twalk	= (struct p9_twalk *)msg->msg;
 	struct p9_rwalk *rwalk	= (struct p9_rwalk *)outmsg->msg;
 	struct p9_str *str	= twalk->wnames;
-	struct p9_fid *new_fid	= &p9dev.fids[twalk->newfid];
+	struct p9_fid *new_fid	= &p9dev->fids[twalk->newfid];
 	u8 i;
 
 	rwalk->nwqid = 0;
 	if (twalk->nwname) {
-		struct p9_fid *fid = &p9dev.fids[twalk->fid];
+		struct p9_fid *fid = &p9dev->fids[twalk->fid];
 
 		for (i = 0; i < twalk->nwname; i++) {
 			char tmp[PATH_MAX] = {0};
@@ -295,7 +308,7 @@  static bool virtio_p9_walk(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *
 			/* Format the new path we're 'walk'ing into */
 			sprintf(tmp, "%s/%.*s", fid->path, str->len, (char *)&str->str);
 
-			if (stat(rel_to_abs(tmp, full_path), &st) < 0)
+			if (stat(rel_to_abs(p9dev, tmp, full_path), &st) < 0)
 				break;
 
 			st2qid(&st, &rwalk->wqids[i]);
@@ -305,8 +318,8 @@  static bool virtio_p9_walk(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *
 			rwalk->nwqid++;
 		}
 	} else {
-		new_fid->is_dir = p9dev.fids[twalk->fid].is_dir;
-		strcpy(new_fid->path, p9dev.fids[twalk->fid].path);
+		new_fid->is_dir = p9dev->fids[twalk->fid].is_dir;
+		strcpy(new_fid->path, p9dev->fids[twalk->fid].path);
 		new_fid->fid	= twalk->newfid;
 	}
 
@@ -316,7 +329,9 @@  static bool virtio_p9_walk(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *
 	return true;
 }
 
-static bool virtio_p9_attach(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
+static bool virtio_p9_attach(struct p9_dev *p9dev, struct p9_msg *msg,
+			     u32 len, struct iovec *iov,
+			     int outiovcnt, int iniovcnt, u32 *outlen)
 {
 	struct p9_msg *outmsg = iov[0].iov_base;
 	struct p9_rattach *rattach = (struct p9_rattach *)outmsg->msg;
@@ -327,14 +342,14 @@  static bool virtio_p9_attach(struct p9_msg *msg, u32 len, struct iovec *iov, u32
 
 	/* Reset everything */
 	for (i = 0; i < VIRTIO_P9_MAX_FID; i++)
-		p9dev.fids[i].fid = P9_NOFID;
+		p9dev->fids[i].fid = P9_NOFID;
 
-	if (stat(p9dev.root_dir, &st) < 0)
+	if (stat(p9dev->root_dir, &st) < 0)
 		return false;
 
 	st2qid(&st, &rattach->qid);
 
-	fid = &p9dev.fids[tattach->fid];
+	fid = &p9dev->fids[tattach->fid];
 	fid->fid = tattach->fid;
 	fid->is_dir = 1;
 	strcpy(fid->path, "/");
@@ -345,7 +360,8 @@  static bool virtio_p9_attach(struct p9_msg *msg, u32 len, struct iovec *iov, u32
 	return true;
 }
 
-static u32 virtio_p9_fill_stat(const char *name, struct stat *st, struct p9_rstat *rstat)
+static u32 virtio_p9_fill_stat(struct p9_dev *p9dev, const char *name,
+			       struct stat *st, struct p9_rstat *rstat)
 {
 	struct p9_str *str;
 
@@ -375,19 +391,24 @@  static u32 virtio_p9_fill_stat(const char *name, struct stat *st, struct p9_rsta
 	str->len = 0;
 	str = (void *)str + sizeof(u16);
 
-	/* We subtract a u16 here because rstat->size doesn't include rstat->size itself */
+	/*
+	 * We subtract a u16 here because rstat->size
+	 * doesn't include rstat->size itself
+	 */
 	rstat->stat.size = (void *)str - (void *)&rstat->stat - sizeof(u16);
 
 	return rstat->stat.size + sizeof(u16);
 }
 
-static bool virtio_p9_read(struct p9_msg *msg, u32 len, struct iovec *iov, int iovcnt, u32 *outlen)
+static bool virtio_p9_read(struct p9_dev *p9dev, struct p9_msg *msg,
+			   u32 len, struct iovec *iov,
+			   int outiovcnt, int iniovcnt, u32 *outlen)
 {
 	struct p9_msg *outmsg	= iov[0].iov_base;
 	struct p9_tread *tread	= (struct p9_tread *)msg->msg;
 	struct p9_rread *rread	= (struct p9_rread *)outmsg->msg;
 	struct p9_rstat *rstat	= (struct p9_rstat *)iov[1].iov_base;
-	struct p9_fid *fid	= &p9dev.fids[tread->fid];
+	struct p9_fid *fid	= &p9dev->fids[tread->fid];
 	struct stat st;
 
 	rread->count = 0;
@@ -400,8 +421,9 @@  static bool virtio_p9_read(struct p9_msg *msg, u32 len, struct iovec *iov, int i
 		while (cur) {
 			u32 read;
 
-			stat(rel_to_abs(cur->d_name, full_path), &st);
-			read = virtio_p9_fill_stat(cur->d_name, &st, rstat);
+			stat(rel_to_abs(p9dev, cur->d_name, full_path), &st);
+			read = virtio_p9_fill_stat(p9dev, cur->d_name,
+						   &st, rstat);
 			rread->count += read;
 			rstat = (void *)rstat + read;
 			cur = readdir(fid->dir);
@@ -409,7 +431,7 @@  static bool virtio_p9_read(struct p9_msg *msg, u32 len, struct iovec *iov, int i
 	} else {
 		iov[0].iov_base += VIRTIO_P9_HDR_LEN + sizeof(u32);
 		iov[0].iov_len -= VIRTIO_P9_HDR_LEN + sizeof(u32);
-		rread->count = preadv(fid->fd, iov, iovcnt, tread->offset);
+		rread->count = preadv(fid->fd, iov, iniovcnt, tread->offset);
 		if (rread->count > tread->count)
 			rread->count = tread->count;
 	}
@@ -420,31 +442,35 @@  static bool virtio_p9_read(struct p9_msg *msg, u32 len, struct iovec *iov, int i
 	return true;
 }
 
-static bool virtio_p9_stat(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
+static bool virtio_p9_stat(struct p9_dev *p9dev, struct p9_msg *msg,
+			   u32 len, struct iovec *iov,
+			   int outiovcnt, int iniovcnt, u32 *outlen)
 {
 	struct p9_msg *outmsg = iov[0].iov_base;
 	struct p9_tstat *tstat = (struct p9_tstat *)msg->msg;
 	struct p9_rstat *rstat = (struct p9_rstat *)(outmsg->msg + sizeof(u16));
 	struct stat st;
-	struct p9_fid *fid = &p9dev.fids[tstat->fid];
+	struct p9_fid *fid = &p9dev->fids[tstat->fid];
 	u32 ret;
 
 	if (stat(fid->abs_path, &st) < 0)
 		return false;
 
-	ret = virtio_p9_fill_stat(fid->path, &st, rstat);
+	ret = virtio_p9_fill_stat(p9dev, fid->path, &st, rstat);
 
 	*outlen = VIRTIO_P9_HDR_LEN + ret + sizeof(u16) * 2;
 	set_p9msg_hdr(outmsg, *outlen, P9_RSTAT, msg->tag);
 	return true;
 }
 
-static bool virtio_p9_wstat(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
+static bool virtio_p9_wstat(struct p9_dev *p9dev, struct p9_msg *msg,
+			    u32 len, struct iovec *iov,
+			    int outiovcnt, int iniovcnt, u32 *outlen)
 {
 	struct p9_msg *outmsg = iov[0].iov_base;
 	struct p9_twstat *twstat = (struct p9_twstat *)msg->msg;
 	struct p9_str *str;
-	struct p9_fid *fid = &p9dev.fids[twstat->fid];
+	struct p9_fid *fid = &p9dev->fids[twstat->fid];
 	int res = 0;
 
 	if (twstat->stat.length != -1UL)
@@ -466,7 +492,7 @@  static bool virtio_p9_wstat(struct p9_msg *msg, u32 len, struct iovec *iov, u32
 		memcpy(new_name + strlen(new_name), &str->str, str->len);
 
 		/* fid is reused for the new file */
-		rename(fid->abs_path, rel_to_abs(new_name, full_path));
+		rename(fid->abs_path, rel_to_abs(p9dev, new_name, full_path));
 		sprintf(fid->path, "%s", new_name);
 	}
 
@@ -476,13 +502,15 @@  static bool virtio_p9_wstat(struct p9_msg *msg, u32 len, struct iovec *iov, u32
 	return res == 0;
 }
 
-static bool virtio_p9_remove(struct p9_msg *msg, u32 len, struct iovec *iov, u32 *outlen)
+static bool virtio_p9_remove(struct p9_dev *p9dev, struct p9_msg *msg,
+			     u32 len, struct iovec *iov,
+			     int outiovcnt, int iniovcnt, u32 *outlen)
 {
 	struct p9_msg *outmsg = iov[0].iov_base;
 	struct p9_tremove *tremove = (struct p9_tremove *)msg->msg;
-	struct p9_fid *fid = &p9dev.fids[tremove->fid];
+	struct p9_fid *fid = &p9dev->fids[tremove->fid];
 
-	close_fid(tremove->fid);
+	close_fid(p9dev, tremove->fid);
 	if (fid->is_dir)
 		rmdir(fid->abs_path);
 	else
@@ -493,131 +521,138 @@  static bool virtio_p9_remove(struct p9_msg *msg, u32 len, struct iovec *iov, u32
 	return true;
 }
 
-static bool virtio_p9_write(struct p9_msg *msg, u32 len, struct iovec *iov, int iovcnt, u32 *outlen)
+static bool virtio_p9_write(struct p9_dev *p9dev, struct p9_msg *msg,
+			    u32 len, struct iovec *iov,
+			    int outiovcnt, int iniovcnt, u32 *outlen)
 {
 	struct p9_msg *outmsg;
 	struct p9_rwrite *rwrite;
 	struct p9_twrite *twrite = (struct p9_twrite *)msg->msg;
-	struct p9_fid *fid = &p9dev.fids[twrite->fid];
+	struct p9_fid *fid = &p9dev->fids[twrite->fid];
 
-	if (iovcnt == 1) {
+	if (outiovcnt == 1) {
 		outmsg = iov[0].iov_base;
 		rwrite = (struct p9_rwrite *)outmsg->msg;
-		rwrite->count = pwrite(fid->fd, &twrite->data, twrite->count, twrite->offset);
+		rwrite->count = pwrite(fid->fd, &twrite->data,
+				       twrite->count, twrite->offset);
 	} else {
 		outmsg = iov[2].iov_base;
 		rwrite = (struct p9_rwrite *)outmsg->msg;
-		rwrite->count = pwrite(fid->fd, iov[1].iov_base, twrite->count, twrite->offset);
+		rwrite->count = pwrite(fid->fd, iov[1].iov_base,
+				       twrite->count, twrite->offset);
 	}
-
 	*outlen = VIRTIO_P9_HDR_LEN + sizeof(u32);
 	set_p9msg_hdr(outmsg, *outlen, P9_RWRITE, msg->tag);
 
 	return true;
 }
 
-static bool virtio_p9_do_io_request(struct kvm *kvm, struct virt_queue *queue)
+typedef bool p9_handler(struct p9_dev *p9dev, struct p9_msg *msg,
+			u32 len, struct iovec *iov,
+			int outiovcnt, int iniovcnt, u32 *outlen);
+
+static p9_handler *virtio_9p_handler [] = {
+	[P9_TVERSION] = virtio_p9_version,
+	[P9_TATTACH]  = virtio_p9_attach,
+	[P9_TSTAT]    = virtio_p9_stat,
+	[P9_TCLUNK]   =	virtio_p9_clunk,
+	[P9_TWALK]    =	virtio_p9_walk,
+	[P9_TOPEN]    =	virtio_p9_open,
+	[P9_TREAD]    = virtio_p9_read,
+	[P9_TCREATE]  =	virtio_p9_create,
+	[P9_TWSTAT]   =	virtio_p9_wstat,
+	[P9_TREMOVE]  =	virtio_p9_remove,
+	[P9_TWRITE]   =	virtio_p9_write,
+};
+
+static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job)
 {
-	struct iovec iov[VIRTIO_P9_QUEUE_SIZE];
+	u32 len = 0;
 	u16 out, in, head;
 	struct p9_msg *msg;
-	u32 len = 0;
+	p9_handler *handler;
+	struct virt_queue *vq;
+	struct p9_dev *p9dev;
+	struct iovec iov[VIRTIO_P9_QUEUE_SIZE];
 
-	head		= virt_queue__get_iov(queue, iov, &out, &in, kvm);
-	msg		= iov[0].iov_base;
+	vq = job->vq;
+	p9dev = job->p9dev;
+	head  = virt_queue__get_iov(vq, iov, &out, &in, kvm);
+	msg   = iov[0].iov_base;
 
-	switch (msg->cmd) {
-	case P9_TVERSION:
-		virtio_p9_version(msg, iov[0].iov_len, iov+1, &len);
-		break;
-	case P9_TATTACH:
-		virtio_p9_attach(msg, iov[0].iov_len, iov+1, &len);
-		break;
-	case P9_TSTAT:
-		virtio_p9_stat(msg, iov[0].iov_len, iov+1, &len);
-		break;
-	case P9_TCLUNK:
-		virtio_p9_clunk(msg, iov[0].iov_len, iov+1, &len);
-		break;
-	case P9_TWALK:
-		virtio_p9_walk(msg, iov[0].iov_len, iov+1, &len);
-		break;
-	case P9_TOPEN:
-		virtio_p9_open(msg, iov[0].iov_len, iov+1, &len);
-		break;
-	case P9_TREAD:
-		virtio_p9_read(msg, iov[0].iov_len, iov+1, in, &len);
-		break;
-	case P9_TCREATE:
-		virtio_p9_create(msg, iov[0].iov_len, iov+1, &len);
-		break;
-	case P9_TWSTAT:
-		virtio_p9_wstat(msg, iov[0].iov_len, iov+1, &len);
-		break;
-	case P9_TREMOVE:
-		virtio_p9_remove(msg, iov[0].iov_len, iov+1, &len);
-		break;
-	case P9_TWRITE:
-		virtio_p9_write(msg, iov[0].iov_len, iov+1, out, &len);
-		break;
-	default:
+	if (msg->cmd >= ARRAY_SIZE(virtio_9p_handler) ||
+	    !virtio_9p_handler[msg->cmd]) {
 		printf("Unsupported P9 message type: %u\n", msg->cmd);
-		break;
-	}
-	virt_queue__set_used_elem(queue, head, len);
 
+	} else {
+		handler = virtio_9p_handler[msg->cmd];
+		handler(p9dev, msg, iov[0].iov_len, iov+1, out, in, &len);
+	}
+	virt_queue__set_used_elem(vq, head, len);
 	return true;
 }
 
 static void virtio_p9_do_io(struct kvm *kvm, void *param)
 {
-	struct virt_queue *vq = param;
+	struct p9_dev_job *job = (struct p9_dev_job *)param;
+	struct p9_dev *p9dev   = job->p9dev;
+	struct virt_queue *vq  = job->vq;
 
 	while (virt_queue__available(vq)) {
-		virtio_p9_do_io_request(kvm, vq);
-		virt_queue__trigger_irq(vq, virtio_p9_pci_device.irq_line, &p9dev.isr, kvm);
+		virtio_p9_do_io_request(kvm, job);
+		virt_queue__trigger_irq(vq, p9dev->pci_hdr.irq_line,
+					&p9dev->isr, kvm);
 	}
 }
 
-static bool virtio_p9_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_p9_pci_io_out(struct ioport *ioport, struct kvm *kvm,
+				 u16 port, void *data, int size, u32 count)
 {
 	unsigned long offset;
 	bool ret = true;
+	struct p9_dev  *p9dev;
 
-	offset = port - p9dev.base_addr;
+	p9dev = ioport->priv;
+	offset = port - p9dev->base_addr;
 
 	switch (offset) {
 	case VIRTIO_MSI_QUEUE_VECTOR:
 	case VIRTIO_PCI_GUEST_FEATURES:
 		break;
 	case VIRTIO_PCI_QUEUE_PFN: {
-		struct virt_queue *queue;
 		void *p;
+		struct p9_dev_job *job;
+		struct virt_queue *queue;
 
-		queue			= &p9dev.vqs[p9dev.queue_selector];
+		job			= &p9dev->jobs[p9dev->queue_selector];
+		queue			= &p9dev->vqs[p9dev->queue_selector];
 		queue->pfn		= ioport__read32(data);
 		p			= guest_pfn_to_host(kvm, queue->pfn);
 
-		vring_init(&queue->vring, VIRTIO_P9_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
-
-		p9dev.jobs[p9dev.queue_selector] = thread_pool__add_job(kvm, virtio_p9_do_io, queue);
+		vring_init(&queue->vring, VIRTIO_P9_QUEUE_SIZE, p,
+			   VIRTIO_PCI_VRING_ALIGN);
 
+		*job			= (struct p9_dev_job) {
+			.vq			= queue,
+			.p9dev			= p9dev,
+		};
+		job->job_id = thread_pool__add_job(kvm, virtio_p9_do_io, job);
 		break;
 	}
 	case VIRTIO_PCI_QUEUE_SEL:
-		p9dev.queue_selector	= ioport__read16(data);
+		p9dev->queue_selector	= ioport__read16(data);
 		break;
 	case VIRTIO_PCI_QUEUE_NOTIFY: {
 		u16 queue_index;
 		queue_index		= ioport__read16(data);
-		thread_pool__do_job(p9dev.jobs[queue_index]);
+		thread_pool__do_job(p9dev->jobs[queue_index].job_id);
 		break;
 	}
 	case VIRTIO_PCI_STATUS:
-		p9dev.status		= ioport__read8(data);
+		p9dev->status		= ioport__read8(data);
 		break;
 	case VIRTIO_MSI_CONFIG_VECTOR:
-		p9dev.config_vector	= VIRTIO_MSI_NO_VECTOR;
+		p9dev->config_vector	= VIRTIO_MSI_NO_VECTOR;
 		break;
 	default:
 		ret			= false;
@@ -632,39 +667,63 @@  static struct ioport_operations virtio_p9_io_ops = {
 	.io_out				= virtio_p9_pci_io_out,
 };
 
-void virtio_9p__init(struct kvm *kvm, const char *root)
+void virtio_9p__init(struct kvm *kvm, const char *root, const char *tag_name)
 {
 	u8 pin, line, dev;
 	u32 i, root_len;
 	u16 p9_base_addr;
+	struct p9_dev *p9dev;
 
-	p9dev.config = calloc(1, sizeof(*p9dev.config) + sizeof(VIRTIO_P9_TAG));
-	if (p9dev.config == NULL)
+	p9dev = calloc(1, sizeof(*p9dev));
+	if (!p9dev)
 		return;
+	if (!tag_name)
+		tag_name = VIRTIO_P9_DEFAULT_TAG;
+	p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1);
+	if (p9dev->config == NULL)
+		goto free_p9dev;
 
-	strcpy(p9dev.root_dir, root);
+	strcpy(p9dev->root_dir, root);
 	root_len = strlen(root);
-
 	/*
 	 * We prefix the full path in all fids, This allows us to get the
 	 * absolute path of an fid without playing with strings.
 	 */
 	for (i = 0; i < VIRTIO_P9_MAX_FID; i++) {
-		strcpy(p9dev.fids[i].abs_path, root);
-		p9dev.fids[i].path = p9dev.fids[i].abs_path + root_len;
+		strcpy(p9dev->fids[i].abs_path, root);
+		p9dev->fids[i].path = p9dev->fids[i].abs_path + root_len;
 	}
+	p9dev->config->tag_len = strlen(tag_name);
+	if (p9dev->config->tag_len > MAX_TAG_LEN)
+		goto free_p9dev_config;
 
-	p9dev.config->tag_len = strlen(VIRTIO_P9_TAG);
-	memcpy(p9dev.config->tag, VIRTIO_P9_TAG, strlen(VIRTIO_P9_TAG));
-	p9dev.features |= 1 << VIRTIO_9P_MOUNT_TAG;
+	memcpy(p9dev->config->tag, tag_name, strlen(tag_name));
+	p9dev->features |= 1 << VIRTIO_9P_MOUNT_TAG;
 
 	if (irq__register_device(VIRTIO_ID_9P, &dev, &pin, &line) < 0)
-		return;
+		goto free_p9dev_config;
+
+	p9_base_addr			= ioport__register(IOPORT_EMPTY,
+							   &virtio_p9_io_ops,
+							   IOPORT_SIZE, p9dev);
+	p9dev->base_addr		    = p9_base_addr;
+	p9dev->pci_hdr = (struct pci_device_header) {
+		.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
+		.device_id		= PCI_DEVICE_ID_VIRTIO_P9,
+		.header_type		= PCI_HEADER_TYPE_NORMAL,
+		.revision_id		= 0,
+		.class			= 0x010000,
+		.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
+		.subsys_id		= VIRTIO_ID_9P,
+		.irq_pin		= pin,
+		.irq_line		= line,
+		.bar[0]			= p9_base_addr | PCI_BASE_ADDRESS_SPACE_IO,
+	};
+	pci__register(&p9dev->pci_hdr, dev);
 
-	virtio_p9_pci_device.irq_pin	= pin;
-	virtio_p9_pci_device.irq_line	= line;
-	p9_base_addr			= ioport__register(IOPORT_EMPTY, &virtio_p9_io_ops, IOPORT_SIZE, NULL);
-	virtio_p9_pci_device.bar[0]	= p9_base_addr | PCI_BASE_ADDRESS_SPACE_IO;
-	p9dev.base_addr			= p9_base_addr;
-	pci__register(&virtio_p9_pci_device, dev);
+	return;
+free_p9dev_config:
+	free(p9dev->config);
+free_p9dev:
+	free(p9dev);
 }