From: Aneesh Kumar K.V Date: Fri, 17 Jun 2011 18:11:22 +0000 (+0530) Subject: tools/kvm/9p: Add support for multiple 9p export dirs X-Git-Tag: next-20110824~3^2~200 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=f40f62a2a688b774ca2710bdcda026d5c3eabf50;p=karo-tx-linux.git tools/kvm/9p: Add support for multiple 9p export dirs Acked-by: Sasha Levin Signed-off-by: Aneesh Kumar K.V Signed-off-by: Pekka Enberg --- diff --git a/tools/kvm/include/kvm/virtio-9p.h b/tools/kvm/include/kvm/virtio-9p.h index 905283039b87..d99bf961d927 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 6ad55aa1d83c..60fc07b55732 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 38a997db7984..d4263d260579 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); }