Message ID | 1309170437-16361-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Mon, 2011-06-27 at 15:57 +0530, Aneesh Kumar K.V wrote: > The protocol data is in little-endian format. > > Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> What about the suggestion regarding using a pipe in the pdu read/write functions? > --- > tools/kvm/Makefile | 1 + > tools/kvm/include/kvm/virtio-9p.h | 80 ++++++- > tools/kvm/virtio/9p-pdu.c | 239 ++++++++++++++++++ > tools/kvm/virtio/9p.c | 479 ++++++++++++++++--------------------- > 4 files changed, 529 insertions(+), 270 deletions(-) > create mode 100644 tools/kvm/virtio/9p-pdu.c > > diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile > index d368c22..559fefc 100644 > --- a/tools/kvm/Makefile > +++ b/tools/kvm/Makefile > @@ -57,6 +57,7 @@ OBJS += util/parse-options.o > OBJS += util/rbtree-interval.o > OBJS += util/strbuf.o > OBJS += virtio/9p.o > +OBJS += virtio/9p-pdu.o > OBJS += hw/vesa.o > OBJS += hw/i8042.o > > diff --git a/tools/kvm/include/kvm/virtio-9p.h b/tools/kvm/include/kvm/virtio-9p.h > index d99bf96..27f52aa 100644 > --- a/tools/kvm/include/kvm/virtio-9p.h > +++ b/tools/kvm/include/kvm/virtio-9p.h > @@ -1,8 +1,86 @@ > #ifndef KVM__VIRTIO_9P_H > #define KVM__VIRTIO_9P_H > +#include "kvm/virtio-pci-dev.h" > +#include "kvm/virtio.h" > +#include "kvm/ioport.h" > +#include "kvm/mutex.h" > +#include "kvm/util.h" > +#include "kvm/kvm.h" > +#include "kvm/pci.h" > +#include "kvm/threadpool.h" > +#include "kvm/irq.h" > +#include "kvm/ioeventfd.h" > + > +#include <fcntl.h> > +#include <sys/types.h> > +#include <sys/stat.h> > +#include <pthread.h> > +#include <dirent.h> > + > +#include <linux/virtio_ring.h> > +#include <linux/virtio_9p.h> > + > +#define NUM_VIRT_QUEUES 1 > +#define VIRTQUEUE_NUM 128 > +#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; > + u8 cmd; > + u16 tag; > + u8 msg[0]; > +} __attribute__((packed)); > + > +struct p9_fid { > + u32 fid; > + u8 is_dir; > + char abs_path[PATH_MAX]; > + char *path; > + DIR *dir; > + int fd; > +}; > + > +struct p9_dev_job { > + struct virt_queue *vq; > + struct p9_dev *p9dev; > + void *job_id; > +}; > + > +struct p9_dev { > + u8 status; > + u8 isr; > + u16 config_vector; > + u32 features; > + struct virtio_9p_config *config; > + u16 base_addr; > + > + /* virtio queue */ > + u16 queue_selector; > + struct virt_queue vqs[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; > +}; > + > +struct p9_pdu { > + u32 queue_head; > + size_t read_offset; > + size_t write_offset; > + u16 out_iov_cnt; > + u16 in_iov_cnt; > + struct iovec in_iov[VIRTQUEUE_NUM]; > + struct iovec out_iov[VIRTQUEUE_NUM]; > +}; > > struct kvm; > > void virtio_9p__init(struct kvm *kvm, const char *root, const char *tag_name); > - > +int virtio_p9_pdu_readf(struct p9_pdu *pdu, const char *fmt, ...); > +int virtio_p9_pdu_writef(struct p9_pdu *pdu, const char *fmt, ...); > #endif > diff --git a/tools/kvm/virtio/9p-pdu.c b/tools/kvm/virtio/9p-pdu.c > new file mode 100644 > index 0000000..07cafd3 > --- /dev/null > +++ b/tools/kvm/virtio/9p-pdu.c > @@ -0,0 +1,239 @@ > +#include "kvm/virtio-9p.h" > + > +#include <endian.h> > + > +#include <net/9p/9p.h> > + > +static void virtio_p9_pdu_read(struct p9_pdu *pdu, void *data, size_t size) > +{ > + size_t len; > + int i, copied = 0; > + u16 iov_cnt = pdu->out_iov_cnt; > + size_t offset = pdu->read_offset; > + struct iovec *iov = pdu->out_iov; > + > + for (i = 0; i < iov_cnt && size; i++) { > + if (offset >= iov[i].iov_len) { > + offset -= iov[i].iov_len; > + continue; > + } else { > + len = MIN(iov[i].iov_len - offset, size); > + memcpy(data, iov[i].iov_base + offset, len); > + size -= len; > + data += len; > + offset = 0; > + copied += len; > + } > + } > + pdu->read_offset += copied; > +} > + > +static void virtio_p9_pdu_write(struct p9_pdu *pdu, > + const void *data, size_t size) > +{ > + size_t len; > + int i, copied = 0; > + u16 iov_cnt = pdu->in_iov_cnt; > + size_t offset = pdu->write_offset; > + struct iovec *iov = pdu->in_iov; > + > + for (i = 0; i < iov_cnt && size; i++) { > + if (offset >= iov[i].iov_len) { > + offset -= iov[i].iov_len; > + continue; > + } else { > + len = MIN(iov[i].iov_len - offset, size); > + memcpy(iov[i].iov_base + offset, data, len); > + size -= len; > + data += len; > + offset = 0; > + copied += len; > + } > + } > + pdu->write_offset += copied; > +} > + > +static void virtio_p9_wstat_free(struct p9_wstat *stbuf) > +{ > + free(stbuf->name); > + free(stbuf->uid); > + free(stbuf->gid); > + free(stbuf->muid); > +} > + > +static int virtio_p9_decode(struct p9_pdu *pdu, const char *fmt, va_list ap) > +{ > + int retval = 0; > + const char *ptr; > + > + for (ptr = fmt; *ptr; ptr++) { > + switch (*ptr) { > + case 'b': > + { > + int8_t *val = va_arg(ap, int8_t *); > + virtio_p9_pdu_read(pdu, val, sizeof(*val)); > + } > + break; > + case 'w': > + { > + int16_t le_val; > + int16_t *val = va_arg(ap, int16_t *); > + virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val)); > + *val = le16toh(le_val); > + } > + break; > + case 'd': > + { > + int32_t le_val; > + int32_t *val = va_arg(ap, int32_t *); > + virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val)); > + *val = le32toh(le_val); > + } > + break; > + case 'q': > + { > + int64_t le_val; > + int64_t *val = va_arg(ap, int64_t *); > + virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val)); > + *val = le64toh(le_val); > + } > + break; > + case 's': > + { > + int16_t len; > + char **str = va_arg(ap, char **); > + > + virtio_p9_pdu_readf(pdu, "w", &len); > + *str = malloc(len + 1); > + if (*str == NULL) { > + retval = ENOMEM; > + break; > + } > + virtio_p9_pdu_read(pdu, *str, len); > + (*str)[len] = 0; > + } > + break; > + case 'Q': > + { > + struct p9_qid *qid = va_arg(ap, struct p9_qid *); > + retval = virtio_p9_pdu_readf(pdu, "bdq", > + &qid->type, &qid->version, > + &qid->path); > + } > + break; > + case 'S': > + { > + struct p9_wstat *stbuf = va_arg(ap, struct p9_wstat *); > + memset(stbuf, 0, sizeof(struct p9_wstat)); > + stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = -1; > + retval = virtio_p9_pdu_readf(pdu, "wwdQdddqssss", > + &stbuf->size, &stbuf->type, > + &stbuf->dev, &stbuf->qid, > + &stbuf->mode, &stbuf->atime, > + &stbuf->mtime, &stbuf->length, > + &stbuf->name, &stbuf->uid, > + &stbuf->gid, &stbuf->muid); > + if (retval) > + virtio_p9_wstat_free(stbuf); > + } > + break; > + default: > + retval = EINVAL; > + break; > + } > + } > + return retval; > +} > + > +static int virtio_p9_pdu_encode(struct p9_pdu *pdu, const char *fmt, va_list ap) > +{ > + int retval = 0; > + const char *ptr; > + > + for (ptr = fmt; *ptr; ptr++) { > + switch (*ptr) { > + case 'b': > + { > + int8_t val = va_arg(ap, int); > + virtio_p9_pdu_write(pdu, &val, sizeof(val)); > + } > + break; > + case 'w': > + { > + int16_t val = htole16(va_arg(ap, int)); > + virtio_p9_pdu_write(pdu, &val, sizeof(val)); > + } > + break; > + case 'd': > + { > + int32_t val = htole32(va_arg(ap, int32_t)); > + virtio_p9_pdu_write(pdu, &val, sizeof(val)); > + } > + break; > + case 'q': > + { > + int64_t val = htole64(va_arg(ap, int64_t)); > + virtio_p9_pdu_write(pdu, &val, sizeof(val)); > + } > + break; > + case 's': > + { > + uint16_t len = 0; > + const char *s = va_arg(ap, char *); > + if (s) > + len = MIN(strlen(s), USHRT_MAX); > + virtio_p9_pdu_writef(pdu, "w", len); > + virtio_p9_pdu_write(pdu, s, len); > + } > + break; > + case 'Q': > + { > + struct p9_qid *qid = va_arg(ap, struct p9_qid *); > + retval = virtio_p9_pdu_writef(pdu, "bdq", > + qid->type, qid->version, > + qid->path); > + } > + break; > + case 'S': > + { > + struct p9_wstat *stbuf = va_arg(ap, struct p9_wstat *); > + retval = virtio_p9_pdu_writef(pdu, "wwdQdddqssss", > + stbuf->size, stbuf->type, > + stbuf->dev, &stbuf->qid, > + stbuf->mode, stbuf->atime, > + stbuf->mtime, stbuf->length, > + stbuf->name, stbuf->uid, > + stbuf->gid, stbuf->muid); > + } > + break; > + default: > + retval = EINVAL; > + break; > + } > + } > + return retval; > +} > + > +int virtio_p9_pdu_readf(struct p9_pdu *pdu, const char *fmt, ...) > +{ > + int ret; > + va_list ap; > + > + va_start(ap, fmt); > + ret = virtio_p9_decode(pdu, fmt, ap); > + va_end(ap); > + > + return ret; > +} > + > +int virtio_p9_pdu_writef(struct p9_pdu *pdu, const char *fmt, ...) > +{ > + int ret; > + va_list ap; > + > + va_start(ap, fmt); > + ret = virtio_p9_pdu_encode(pdu, fmt, ap); > + va_end(ap); > + > + return ret; > +} > diff --git a/tools/kvm/virtio/9p.c b/tools/kvm/virtio/9p.c > index d2d738d..a08d7ec 100644 > --- a/tools/kvm/virtio/9p.c > +++ b/tools/kvm/virtio/9p.c > @@ -1,81 +1,6 @@ > #include "kvm/virtio-9p.h" > -#include "kvm/virtio-pci-dev.h" > -#include "kvm/virtio.h" > -#include "kvm/ioport.h" > -#include "kvm/mutex.h" > -#include "kvm/util.h" > -#include "kvm/kvm.h" > -#include "kvm/pci.h" > -#include "kvm/threadpool.h" > -#include "kvm/irq.h" > -#include "kvm/ioeventfd.h" > - > -#include <fcntl.h> > -#include <sys/types.h> > -#include <sys/stat.h> > -#include <pthread.h> > -#include <dirent.h> > - > -#include <linux/virtio_ring.h> > -#include <linux/virtio_9p.h> > -#include <net/9p/9p.h> > - > -#define NUM_VIRT_QUEUES 1 > -#define VIRTQUEUE_NUM 128 > -#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; > - u8 cmd; > - u16 tag; > - u8 msg[0]; > -} __attribute__((packed)); > - > -struct p9_fid { > - u32 fid; > - u8 is_dir; > - char abs_path[PATH_MAX]; > - char *path; > - DIR *dir; > - int fd; > -}; > - > -struct p9_dev_job { > - struct virt_queue *vq; > - struct p9_dev *p9dev; > - void *job_id; > -}; > - > -struct p9_dev { > - u8 status; > - u8 isr; > - u16 config_vector; > - u32 features; > - struct virtio_9p_config *config; > - u16 base_addr; > - > - /* virtio queue */ > - u16 queue_selector; > - struct virt_queue vqs[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; > -}; > > -struct p9_pdu { > - u32 queue_head; > - int offset; > - u16 out_iov_cnt; > - u16 in_iov_cnt; > - struct iovec in_iov[VIRTQUEUE_NUM]; > - struct iovec out_iov[VIRTQUEUE_NUM]; > -}; > +#include <net/9p/9p.h> > > /* Warning: Immediately use value returned from this function */ > static const char *rel_to_abs(struct p9_dev *p9dev, > @@ -185,13 +110,16 @@ static void close_fid(struct p9_dev *p9dev, u32 fid) > } > } > > -static void set_p9msg_hdr(struct p9_msg *msg, u32 size, u8 cmd, u16 tag) > +static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size) > { > - *msg = (struct p9_msg) { > - .size = size, > - .tag = tag, > - .cmd = cmd, > - }; > + u8 cmd; > + u16 tag; > + > + pdu->read_offset = sizeof(u32); > + virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag); > + pdu->write_offset = 0; > + /* cmd + 1 is the reply message */ > + virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag); > } > > static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) > @@ -213,67 +141,61 @@ static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) > static void virtio_p9_error_reply(struct p9_dev *p9dev, > struct p9_pdu *pdu, int err, u32 *outlen) > { > + u16 tag; > char *err_str; > - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; > - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; > - struct p9_rerror *rerror = (struct p9_rerror *)inmsg->msg; > > err_str = strerror(err); > - rerror->error.len = strlen(err_str); > - memcpy(&rerror->error.str, err_str, rerror->error.len); > + pdu->write_offset = VIRTIO_P9_HDR_LEN; > + virtio_p9_pdu_writef(pdu, "s", err_str); > + *outlen = pdu->write_offset; > + > + pdu->read_offset = sizeof(u32) + sizeof(u8); > + virtio_p9_pdu_readf(pdu, "w", &tag); > > - *outlen = VIRTIO_P9_HDR_LEN + rerror->error.len + sizeof(u16); > - set_p9msg_hdr(inmsg, *outlen, P9_RERROR, outmsg->tag); > + pdu->write_offset = 0; > + virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RERROR, tag); > } > > static void virtio_p9_version(struct p9_dev *p9dev, > struct p9_pdu *pdu, u32 *outlen) > { > - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; > - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; > - struct p9_rversion *rversion = (struct p9_rversion *)inmsg->msg; > - > - rversion->msize = 4096; > - 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); > - set_p9msg_hdr(inmsg, *outlen, P9_RVERSION, outmsg->tag); > + virtio_p9_pdu_writef(pdu, "ds", 4096, VIRTIO_P9_VERSION); > > + *outlen = pdu->write_offset; > + virtio_p9_set_reply_header(pdu, *outlen); > return; > } > > static void virtio_p9_clunk(struct p9_dev *p9dev, > struct p9_pdu *pdu, u32 *outlen) > { > - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; > - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; > - struct p9_tclunk *tclunk = (struct p9_tclunk *)outmsg->msg; > - > - close_fid(p9dev, tclunk->fid); > + u32 fid; > > - *outlen = VIRTIO_P9_HDR_LEN; > - set_p9msg_hdr(inmsg, *outlen, P9_RCLUNK, outmsg->tag); > + virtio_p9_pdu_readf(pdu, "d", &fid); > + close_fid(p9dev, fid); > > + *outlen = pdu->write_offset; > + virtio_p9_set_reply_header(pdu, *outlen); > return; > } > > static void virtio_p9_open(struct p9_dev *p9dev, > struct p9_pdu *pdu, u32 *outlen) > { > + u8 mode; > + u32 fid; > struct stat st; > - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; > - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; > - struct p9_topen *topen = (struct p9_topen *)outmsg->msg; > - struct p9_ropen *ropen = (struct p9_ropen *)inmsg->msg; > - struct p9_fid *new_fid = &p9dev->fids[topen->fid]; > + struct p9_qid qid; > + struct p9_fid *new_fid; > + > + > + virtio_p9_pdu_readf(pdu, "db", &fid, &mode); > + new_fid = &p9dev->fids[fid]; > > if (lstat(new_fid->abs_path, &st) < 0) > goto err_out; > > - st2qid(&st, &ropen->qid); > - ropen->iounit = 0; > + st2qid(&st, &qid); > > if (new_fid->is_dir) { > new_fid->dir = opendir(new_fid->abs_path); > @@ -281,12 +203,14 @@ static void virtio_p9_open(struct p9_dev *p9dev, > goto err_out; > } else { > new_fid->fd = open(new_fid->abs_path, > - omode2uflags(topen->mode) | O_NOFOLLOW); > + omode2uflags(mode) | O_NOFOLLOW); > if (new_fid->fd < 0) > goto err_out; > } > - *outlen = VIRTIO_P9_HDR_LEN + sizeof(*ropen); > - set_p9msg_hdr(inmsg, *outlen, P9_ROPEN, outmsg->tag); > + virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); > + > + *outlen = pdu->write_offset; > + virtio_p9_set_reply_header(pdu, *outlen); > return; > err_out: > virtio_p9_error_reply(p9dev, pdu, errno, outlen); > @@ -298,39 +222,33 @@ static void virtio_p9_create(struct p9_dev *p9dev, > { > u8 mode; > u32 perm; > + char *name; > + u32 fid_val; > struct stat st; > - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; > - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; > - struct p9_tcreate *tcreate = (struct p9_tcreate *)outmsg->msg; > - struct p9_rcreate *rcreate = (struct p9_rcreate *)inmsg->msg; > - struct p9_fid *fid = &p9dev->fids[tcreate->fid]; > - > - > - rcreate->iounit = 0; > - > - /* Get last byte of the variable length struct */ > - mode = *((u8 *)outmsg + outmsg->size - 1); > - perm = *(u32 *)((u8 *)outmsg + outmsg->size - 5); > + struct p9_qid qid; > + struct p9_fid *fid; > > - sprintf(fid->path, "%s/%.*s", fid->path, tcreate->name.len, (char *)&tcreate->name.str); > + virtio_p9_pdu_readf(pdu, "dsdb", &fid_val, &name, &perm, &mode); > + fid = &p9dev->fids[fid_val]; > > - close_fid(p9dev, tcreate->fid); > + sprintf(fid->path, "%s/%.*s", fid->path, (int)strlen(name), name); > + close_fid(p9dev, fid_val); > > if (perm & P9_DMDIR) { > mkdir(fid->abs_path, perm & 0xFFFF); > fid->dir = opendir(fid->abs_path); > fid->is_dir = 1; > } else { > - fid->fd = open(fid->abs_path, omode2uflags(mode) | O_CREAT, 0777); > + fid->fd = open(fid->abs_path, > + omode2uflags(mode) | O_CREAT, 0777); > } > - > if (lstat(fid->abs_path, &st) < 0) > goto err_out; > > - st2qid(&st, &rcreate->qid); > - > - *outlen = VIRTIO_P9_HDR_LEN + sizeof(*rcreate); > - set_p9msg_hdr(inmsg, *outlen, P9_RCREATE, outmsg->tag); > + st2qid(&st, &qid); > + virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); > + *outlen = pdu->write_offset; > + virtio_p9_set_reply_header(pdu, *outlen); > return; > err_out: > virtio_p9_error_reply(p9dev, pdu, errno, outlen); > @@ -341,45 +259,57 @@ static void virtio_p9_walk(struct p9_dev *p9dev, > struct p9_pdu *pdu, u32 *outlen) > { > u8 i; > - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; > - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; > - struct p9_twalk *twalk = (struct p9_twalk *)outmsg->msg; > - struct p9_rwalk *rwalk = (struct p9_rwalk *)inmsg->msg; > - struct p9_str *str = twalk->wnames; > - struct p9_fid *new_fid = &p9dev->fids[twalk->newfid]; > + u16 nwqid; > + char *str; > + u16 nwname; > + u32 fid_val; > + u32 newfid_val; > + struct p9_qid wqid; > + struct p9_fid *new_fid; > + > > + virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname); > + new_fid = &p9dev->fids[newfid_val]; > > - rwalk->nwqid = 0; > - if (twalk->nwname) { > - struct p9_fid *fid = &p9dev->fids[twalk->fid]; > + nwqid = 0; > + if (nwname) { > + struct p9_fid *fid = &p9dev->fids[fid_val]; > > - for (i = 0; i < twalk->nwname; i++) { > + /* skip the space for count */ > + pdu->write_offset += sizeof(u16); > + for (i = 0; i < nwname; i++) { > + struct stat st; > char tmp[PATH_MAX] = {0}; > char full_path[PATH_MAX]; > - struct stat st; > > - /* Format the new path we're 'walk'ing into */ > - sprintf(tmp, "%s/%.*s", fid->path, > - str->len, (char *)&str->str); > + virtio_p9_pdu_readf(pdu, "s", &str); > > + /* Format the new path we're 'walk'ing into */ > + sprintf(tmp, "%s/%.*s", > + fid->path, (int)strlen(str), str); > if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0) > goto err_out; > > - st2qid(&st, &rwalk->wqids[i]); > + st2qid(&st, &wqid); > new_fid->is_dir = S_ISDIR(st.st_mode); > strcpy(new_fid->path, tmp); > - new_fid->fid = twalk->newfid; > - rwalk->nwqid++; > + new_fid->fid = newfid_val; > + nwqid++; > + virtio_p9_pdu_writef(pdu, "Q", &wqid); > } > } else { > - new_fid->is_dir = p9dev->fids[twalk->fid].is_dir; > - strcpy(new_fid->path, p9dev->fids[twalk->fid].path); > - new_fid->fid = twalk->newfid; > + /* > + * update write_offset so our outlen get correct value > + */ > + pdu->write_offset += sizeof(u16); > + new_fid->is_dir = p9dev->fids[fid_val].is_dir; > + strcpy(new_fid->path, p9dev->fids[fid_val].path); > + new_fid->fid = newfid_val; > } > - > - *outlen = VIRTIO_P9_HDR_LEN + sizeof(u16) + > - sizeof(struct p9_qid)*rwalk->nwqid; > - set_p9msg_hdr(inmsg, *outlen, P9_RWALK, outmsg->tag); > + *outlen = pdu->write_offset; > + pdu->write_offset = VIRTIO_P9_HDR_LEN; > + virtio_p9_pdu_writef(pdu, "d", nwqid); > + virtio_p9_set_reply_header(pdu, *outlen); > return; > err_out: > virtio_p9_error_reply(p9dev, pdu, errno, outlen); > @@ -390,12 +320,15 @@ static void virtio_p9_attach(struct p9_dev *p9dev, > struct p9_pdu *pdu, u32 *outlen) > { > u32 i; > + u32 fid_val; > + u32 afid; > + char *uname; > + char *aname; > struct stat st; > + struct p9_qid qid; > struct p9_fid *fid; > - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; > - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; > - struct p9_rattach *rattach = (struct p9_rattach *)inmsg->msg; > - struct p9_tattach *tattach = (struct p9_tattach *)outmsg->msg; > + > + virtio_p9_pdu_readf(pdu, "ddss", &fid_val, &afid, &uname, &aname); > > /* Reset everything */ > for (i = 0; i < VIRTIO_P9_MAX_FID; i++) > @@ -404,103 +337,106 @@ static void virtio_p9_attach(struct p9_dev *p9dev, > if (lstat(p9dev->root_dir, &st) < 0) > goto err_out; > > - st2qid(&st, &rattach->qid); > + st2qid(&st, &qid); > > - fid = &p9dev->fids[tattach->fid]; > - fid->fid = tattach->fid; > + fid = &p9dev->fids[fid_val]; > + fid->fid = fid_val; > fid->is_dir = 1; > strcpy(fid->path, "/"); > > - *outlen = VIRTIO_P9_HDR_LEN + sizeof(*rattach); > - set_p9msg_hdr(inmsg, *outlen, P9_RATTACH, outmsg->tag); > + virtio_p9_pdu_writef(pdu, "Q", &qid); > + *outlen = pdu->write_offset; > + virtio_p9_set_reply_header(pdu, *outlen); > return; > err_out: > virtio_p9_error_reply(p9dev, pdu, errno, outlen); > return; > } > > -static u32 virtio_p9_fill_stat(struct p9_dev *p9dev, const char *name, > - struct stat *st, struct p9_rstat *rstat) > +static void virtio_p9_fill_stat(struct p9_dev *p9dev, const char *name, > + struct stat *st, struct p9_wstat *wstat) > { > - struct p9_str *str; > - > - rstat->stat.type = 0; > - rstat->stat.dev = 0; > - st2qid(st, &rstat->stat.qid); > - rstat->stat.mode = st->st_mode; > - rstat->stat.length = st->st_size; > + wstat->type = 0; > + wstat->dev = 0; > + st2qid(st, &wstat->qid); > + wstat->mode = st->st_mode; > + wstat->length = st->st_size; > if (S_ISDIR(st->st_mode)) { > - rstat->stat.length = 0; > - rstat->stat.mode |= P9_DMDIR; > + wstat->length = 0; > + wstat->mode |= P9_DMDIR; > } > > - rstat->stat.atime = st->st_atime; > - rstat->stat.mtime = st->st_mtime; > - > - str = (struct p9_str *)&rstat->stat.name; > - str->len = strlen(name); > - memcpy(&str->str, name, str->len); > - str = (void *)str + str->len + sizeof(u16); > - > - /* TODO: Pass usernames to the client */ > - str->len = 0; > - str = (void *)str + sizeof(u16); > - str->len = 0; > - str = (void *)str + sizeof(u16); > - str->len = 0; > - str = (void *)str + sizeof(u16); > - > - /* > - * 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); > + wstat->atime = st->st_atime; > + wstat->mtime = st->st_mtime; > + > + wstat->name = strdup(name); > + wstat->uid = NULL; > + wstat->gid = NULL; > + wstat->muid = NULL; > + > + /* NOTE: size shouldn't include its own length */ > + /* size[2] type[2] dev[4] qid[13] */ > + /* mode[4] atime[4] mtime[4] length[8]*/ > + /* name[s] uid[s] gid[s] muid[s] */ > + wstat->size = 2+4+13+4+4+4+8+2+2+2+2; > + if (wstat->name) > + wstat->size += strlen(wstat->name); > } > > static void virtio_p9_read(struct p9_dev *p9dev, > struct p9_pdu *pdu, u32 *outlen) > { > - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; > - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; > - struct p9_tread *tread = (struct p9_tread *)outmsg->msg; > - struct p9_rread *rread = (struct p9_rread *)inmsg->msg; > - struct p9_rstat *rstat = (struct p9_rstat *)pdu->in_iov[1].iov_base; > - struct p9_fid *fid = &p9dev->fids[tread->fid]; > + u64 offset; > + u32 fid_val; > + u32 count, rcount; > struct stat st; > + struct p9_fid *fid; > + struct p9_wstat wstat; > > - rread->count = 0; > - > + rcount = 0; > + virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); > + fid = &p9dev->fids[fid_val]; > if (fid->is_dir) { > /* If reading a dir, fill the buffer with p9_stat entries */ > - struct dirent *cur = readdir(fid->dir); > char full_path[PATH_MAX]; > + struct dirent *cur = readdir(fid->dir); > > + /* Skip the space for writing count */ > + pdu->write_offset += sizeof(u32); > while (cur) { > u32 read; > > lstat(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; > + virtio_p9_fill_stat(p9dev, cur->d_name, &st, &wstat); > + > + read = pdu->write_offset; > + virtio_p9_pdu_writef(pdu, "S", &wstat); > + rcount += pdu->write_offset - read; > + > cur = readdir(fid->dir); > } > } else { > pdu->in_iov[0].iov_base += VIRTIO_P9_HDR_LEN + sizeof(u32); > pdu->in_iov[0].iov_len -= VIRTIO_P9_HDR_LEN + sizeof(u32); > pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov, > - tread->count, > - pdu->in_iov_cnt); > - rread->count = preadv(fid->fd, pdu->in_iov, > - pdu->in_iov_cnt, tread->offset); > - if (rread->count > tread->count) > - rread->count = tread->count; > - } > + count, > + pdu->in_iov_cnt); > + rcount = preadv(fid->fd, pdu->in_iov, > + pdu->in_iov_cnt, offset); > + if (rcount > count) > + rcount = count; > + /* > + * Update the iov_base back, so that rest of > + * pdu_writef works correctly. > + */ > + pdu->in_iov[0].iov_base -= VIRTIO_P9_HDR_LEN + sizeof(u32); > + pdu->in_iov[0].iov_len += VIRTIO_P9_HDR_LEN + sizeof(u32); > > - *outlen = VIRTIO_P9_HDR_LEN + sizeof(u32) + rread->count; > - set_p9msg_hdr(inmsg, *outlen, P9_RREAD, outmsg->tag); > + } > + pdu->write_offset = VIRTIO_P9_HDR_LEN; > + virtio_p9_pdu_writef(pdu, "d", rcount); > + *outlen = pdu->write_offset + rcount; > + virtio_p9_set_reply_header(pdu, *outlen); > > return; > } > @@ -508,21 +444,21 @@ static void virtio_p9_read(struct p9_dev *p9dev, > static void virtio_p9_stat(struct p9_dev *p9dev, > struct p9_pdu *pdu, u32 *outlen) > { > - u32 ret; > + u32 fid_val; > struct stat st; > - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; > - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; > - struct p9_tstat *tstat = (struct p9_tstat *)outmsg->msg; > - struct p9_rstat *rstat = (struct p9_rstat *)(inmsg->msg + sizeof(u16)); > - struct p9_fid *fid = &p9dev->fids[tstat->fid]; > + struct p9_fid *fid; > + struct p9_wstat wstat; > > + virtio_p9_pdu_readf(pdu, "d", &fid_val); > + fid = &p9dev->fids[fid_val]; > if (lstat(fid->abs_path, &st) < 0) > goto err_out; > > - ret = virtio_p9_fill_stat(p9dev, fid->path, &st, rstat); > + virtio_p9_fill_stat(p9dev, fid->path, &st, &wstat); > > - *outlen = VIRTIO_P9_HDR_LEN + ret + sizeof(u16); > - set_p9msg_hdr(inmsg, *outlen, P9_RSTAT, outmsg->tag); > + virtio_p9_pdu_writef(pdu, "wS", 0, &wstat); > + *outlen = pdu->write_offset; > + virtio_p9_set_reply_header(pdu, *outlen); > return; > err_out: > virtio_p9_error_reply(p9dev, pdu, errno, outlen); > @@ -533,21 +469,21 @@ static void virtio_p9_wstat(struct p9_dev *p9dev, > struct p9_pdu *pdu, u32 *outlen) > { > int res = 0; > - struct p9_str *str; > - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; > - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; > - struct p9_twstat *twstat = (struct p9_twstat *)outmsg->msg; > - struct p9_fid *fid = &p9dev->fids[twstat->fid]; > + u32 fid_val; > + u16 unused; > + struct p9_fid *fid; > + struct p9_wstat wstat; > > + virtio_p9_pdu_readf(pdu, "dwS", &fid_val, &unused, &wstat); > + fid = &p9dev->fids[fid_val]; > > - if (twstat->stat.length != -1UL) > - res = ftruncate(fid->fd, twstat->stat.length); > + if (wstat.length != -1UL) > + res = ftruncate(fid->fd, wstat.length); > > - if (twstat->stat.mode != -1U) > - chmod(fid->abs_path, twstat->stat.mode & 0xFFFF); > + if (wstat.mode != -1U) > + chmod(fid->abs_path, wstat.mode & 0xFFFF); > > - str = (void *)&twstat->stat.name + sizeof(u16); > - if (str->len > 0) { > + if (strlen(wstat.name) > 0) { > char new_name[PATH_MAX] = {0}; > char full_path[PATH_MAX]; > char *last_dir = strrchr(fid->path, '/'); > @@ -556,57 +492,59 @@ static void virtio_p9_wstat(struct p9_dev *p9dev, > if (last_dir) > strncpy(new_name, fid->path, last_dir - fid->path + 1); > > - memcpy(new_name + strlen(new_name), &str->str, str->len); > + memcpy(new_name + strlen(new_name), > + wstat.name, strlen(wstat.name)); > > /* fid is reused for the new file */ > rename(fid->abs_path, rel_to_abs(p9dev, new_name, full_path)); > sprintf(fid->path, "%s", new_name); > } > - > *outlen = VIRTIO_P9_HDR_LEN; > - set_p9msg_hdr(inmsg, *outlen, P9_RWSTAT, outmsg->tag); > - > + virtio_p9_set_reply_header(pdu, *outlen); > return; > } > > static void virtio_p9_remove(struct p9_dev *p9dev, > struct p9_pdu *pdu, u32 *outlen) > { > - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; > - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; > - struct p9_tremove *tremove = (struct p9_tremove *)outmsg->msg; > - struct p9_fid *fid = &p9dev->fids[tremove->fid]; > + u32 fid_val; > + struct p9_fid *fid; > > - close_fid(p9dev, tremove->fid); > + virtio_p9_pdu_readf(pdu, "d", &fid_val); > + fid = &p9dev->fids[fid_val]; > + close_fid(p9dev, fid_val); > if (fid->is_dir) > rmdir(fid->abs_path); > else > unlink(fid->abs_path); > > *outlen = VIRTIO_P9_HDR_LEN; > - set_p9msg_hdr(inmsg, *outlen, P9_RREMOVE, outmsg->tag); > + virtio_p9_set_reply_header(pdu, *outlen); > return; > } > > static void virtio_p9_write(struct p9_dev *p9dev, > struct p9_pdu *pdu, u32 *outlen) > { > - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; > - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; > - struct p9_twrite *twrite = (struct p9_twrite *)outmsg->msg; > - struct p9_rwrite *rwrite = (struct p9_rwrite *)inmsg->msg; > - struct p9_fid *fid = &p9dev->fids[twrite->fid]; > + u64 offset; > + u32 fid_val; > + u32 count, rcount; > + struct p9_fid *fid; > > + virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); > + fid = &p9dev->fids[fid_val]; > > - pdu->out_iov[0].iov_base += (sizeof(*outmsg) + sizeof(*twrite)); > - pdu->out_iov[0].iov_len -= (sizeof(*outmsg) + sizeof(*twrite)); > - pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, twrite->count, > + /* Adjust the iovec to skip the header and meta data */ > + pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + > + sizeof(struct p9_twrite)); > + pdu->out_iov[0].iov_len -= (sizeof(struct p9_msg) + > + sizeof(struct p9_twrite)); > + pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count, > pdu->out_iov_cnt); > - rwrite->count = pwritev(fid->fd, pdu->out_iov, > - pdu->out_iov_cnt, twrite->offset); > - *outlen = VIRTIO_P9_HDR_LEN + sizeof(u32); > - set_p9msg_hdr(inmsg, *outlen, P9_RWRITE, outmsg->tag); > - > + rcount = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset); > + virtio_p9_pdu_writef(pdu, "d", rcount); > + *outlen = pdu->write_offset; > + virtio_p9_set_reply_header(pdu, *outlen); > return; > } > > @@ -633,6 +571,9 @@ static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq) > if (!pdu) > return NULL; > > + /* skip the pdu header p9_msg */ > + pdu->read_offset = VIRTIO_P9_HDR_LEN; > + pdu->write_offset = VIRTIO_P9_HDR_LEN; > pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov, > pdu->out_iov, > &pdu->in_iov_cnt,
diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile index d368c22..559fefc 100644 --- a/tools/kvm/Makefile +++ b/tools/kvm/Makefile @@ -57,6 +57,7 @@ OBJS += util/parse-options.o OBJS += util/rbtree-interval.o OBJS += util/strbuf.o OBJS += virtio/9p.o +OBJS += virtio/9p-pdu.o OBJS += hw/vesa.o OBJS += hw/i8042.o diff --git a/tools/kvm/include/kvm/virtio-9p.h b/tools/kvm/include/kvm/virtio-9p.h index d99bf96..27f52aa 100644 --- a/tools/kvm/include/kvm/virtio-9p.h +++ b/tools/kvm/include/kvm/virtio-9p.h @@ -1,8 +1,86 @@ #ifndef KVM__VIRTIO_9P_H #define KVM__VIRTIO_9P_H +#include "kvm/virtio-pci-dev.h" +#include "kvm/virtio.h" +#include "kvm/ioport.h" +#include "kvm/mutex.h" +#include "kvm/util.h" +#include "kvm/kvm.h" +#include "kvm/pci.h" +#include "kvm/threadpool.h" +#include "kvm/irq.h" +#include "kvm/ioeventfd.h" + +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <pthread.h> +#include <dirent.h> + +#include <linux/virtio_ring.h> +#include <linux/virtio_9p.h> + +#define NUM_VIRT_QUEUES 1 +#define VIRTQUEUE_NUM 128 +#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; + u8 cmd; + u16 tag; + u8 msg[0]; +} __attribute__((packed)); + +struct p9_fid { + u32 fid; + u8 is_dir; + char abs_path[PATH_MAX]; + char *path; + DIR *dir; + int fd; +}; + +struct p9_dev_job { + struct virt_queue *vq; + struct p9_dev *p9dev; + void *job_id; +}; + +struct p9_dev { + u8 status; + u8 isr; + u16 config_vector; + u32 features; + struct virtio_9p_config *config; + u16 base_addr; + + /* virtio queue */ + u16 queue_selector; + struct virt_queue vqs[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; +}; + +struct p9_pdu { + u32 queue_head; + size_t read_offset; + size_t write_offset; + u16 out_iov_cnt; + u16 in_iov_cnt; + struct iovec in_iov[VIRTQUEUE_NUM]; + struct iovec out_iov[VIRTQUEUE_NUM]; +}; struct kvm; void virtio_9p__init(struct kvm *kvm, const char *root, const char *tag_name); - +int virtio_p9_pdu_readf(struct p9_pdu *pdu, const char *fmt, ...); +int virtio_p9_pdu_writef(struct p9_pdu *pdu, const char *fmt, ...); #endif diff --git a/tools/kvm/virtio/9p-pdu.c b/tools/kvm/virtio/9p-pdu.c new file mode 100644 index 0000000..07cafd3 --- /dev/null +++ b/tools/kvm/virtio/9p-pdu.c @@ -0,0 +1,239 @@ +#include "kvm/virtio-9p.h" + +#include <endian.h> + +#include <net/9p/9p.h> + +static void virtio_p9_pdu_read(struct p9_pdu *pdu, void *data, size_t size) +{ + size_t len; + int i, copied = 0; + u16 iov_cnt = pdu->out_iov_cnt; + size_t offset = pdu->read_offset; + struct iovec *iov = pdu->out_iov; + + for (i = 0; i < iov_cnt && size; i++) { + if (offset >= iov[i].iov_len) { + offset -= iov[i].iov_len; + continue; + } else { + len = MIN(iov[i].iov_len - offset, size); + memcpy(data, iov[i].iov_base + offset, len); + size -= len; + data += len; + offset = 0; + copied += len; + } + } + pdu->read_offset += copied; +} + +static void virtio_p9_pdu_write(struct p9_pdu *pdu, + const void *data, size_t size) +{ + size_t len; + int i, copied = 0; + u16 iov_cnt = pdu->in_iov_cnt; + size_t offset = pdu->write_offset; + struct iovec *iov = pdu->in_iov; + + for (i = 0; i < iov_cnt && size; i++) { + if (offset >= iov[i].iov_len) { + offset -= iov[i].iov_len; + continue; + } else { + len = MIN(iov[i].iov_len - offset, size); + memcpy(iov[i].iov_base + offset, data, len); + size -= len; + data += len; + offset = 0; + copied += len; + } + } + pdu->write_offset += copied; +} + +static void virtio_p9_wstat_free(struct p9_wstat *stbuf) +{ + free(stbuf->name); + free(stbuf->uid); + free(stbuf->gid); + free(stbuf->muid); +} + +static int virtio_p9_decode(struct p9_pdu *pdu, const char *fmt, va_list ap) +{ + int retval = 0; + const char *ptr; + + for (ptr = fmt; *ptr; ptr++) { + switch (*ptr) { + case 'b': + { + int8_t *val = va_arg(ap, int8_t *); + virtio_p9_pdu_read(pdu, val, sizeof(*val)); + } + break; + case 'w': + { + int16_t le_val; + int16_t *val = va_arg(ap, int16_t *); + virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val)); + *val = le16toh(le_val); + } + break; + case 'd': + { + int32_t le_val; + int32_t *val = va_arg(ap, int32_t *); + virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val)); + *val = le32toh(le_val); + } + break; + case 'q': + { + int64_t le_val; + int64_t *val = va_arg(ap, int64_t *); + virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val)); + *val = le64toh(le_val); + } + break; + case 's': + { + int16_t len; + char **str = va_arg(ap, char **); + + virtio_p9_pdu_readf(pdu, "w", &len); + *str = malloc(len + 1); + if (*str == NULL) { + retval = ENOMEM; + break; + } + virtio_p9_pdu_read(pdu, *str, len); + (*str)[len] = 0; + } + break; + case 'Q': + { + struct p9_qid *qid = va_arg(ap, struct p9_qid *); + retval = virtio_p9_pdu_readf(pdu, "bdq", + &qid->type, &qid->version, + &qid->path); + } + break; + case 'S': + { + struct p9_wstat *stbuf = va_arg(ap, struct p9_wstat *); + memset(stbuf, 0, sizeof(struct p9_wstat)); + stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = -1; + retval = virtio_p9_pdu_readf(pdu, "wwdQdddqssss", + &stbuf->size, &stbuf->type, + &stbuf->dev, &stbuf->qid, + &stbuf->mode, &stbuf->atime, + &stbuf->mtime, &stbuf->length, + &stbuf->name, &stbuf->uid, + &stbuf->gid, &stbuf->muid); + if (retval) + virtio_p9_wstat_free(stbuf); + } + break; + default: + retval = EINVAL; + break; + } + } + return retval; +} + +static int virtio_p9_pdu_encode(struct p9_pdu *pdu, const char *fmt, va_list ap) +{ + int retval = 0; + const char *ptr; + + for (ptr = fmt; *ptr; ptr++) { + switch (*ptr) { + case 'b': + { + int8_t val = va_arg(ap, int); + virtio_p9_pdu_write(pdu, &val, sizeof(val)); + } + break; + case 'w': + { + int16_t val = htole16(va_arg(ap, int)); + virtio_p9_pdu_write(pdu, &val, sizeof(val)); + } + break; + case 'd': + { + int32_t val = htole32(va_arg(ap, int32_t)); + virtio_p9_pdu_write(pdu, &val, sizeof(val)); + } + break; + case 'q': + { + int64_t val = htole64(va_arg(ap, int64_t)); + virtio_p9_pdu_write(pdu, &val, sizeof(val)); + } + break; + case 's': + { + uint16_t len = 0; + const char *s = va_arg(ap, char *); + if (s) + len = MIN(strlen(s), USHRT_MAX); + virtio_p9_pdu_writef(pdu, "w", len); + virtio_p9_pdu_write(pdu, s, len); + } + break; + case 'Q': + { + struct p9_qid *qid = va_arg(ap, struct p9_qid *); + retval = virtio_p9_pdu_writef(pdu, "bdq", + qid->type, qid->version, + qid->path); + } + break; + case 'S': + { + struct p9_wstat *stbuf = va_arg(ap, struct p9_wstat *); + retval = virtio_p9_pdu_writef(pdu, "wwdQdddqssss", + stbuf->size, stbuf->type, + stbuf->dev, &stbuf->qid, + stbuf->mode, stbuf->atime, + stbuf->mtime, stbuf->length, + stbuf->name, stbuf->uid, + stbuf->gid, stbuf->muid); + } + break; + default: + retval = EINVAL; + break; + } + } + return retval; +} + +int virtio_p9_pdu_readf(struct p9_pdu *pdu, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = virtio_p9_decode(pdu, fmt, ap); + va_end(ap); + + return ret; +} + +int virtio_p9_pdu_writef(struct p9_pdu *pdu, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = virtio_p9_pdu_encode(pdu, fmt, ap); + va_end(ap); + + return ret; +} diff --git a/tools/kvm/virtio/9p.c b/tools/kvm/virtio/9p.c index d2d738d..a08d7ec 100644 --- a/tools/kvm/virtio/9p.c +++ b/tools/kvm/virtio/9p.c @@ -1,81 +1,6 @@ #include "kvm/virtio-9p.h" -#include "kvm/virtio-pci-dev.h" -#include "kvm/virtio.h" -#include "kvm/ioport.h" -#include "kvm/mutex.h" -#include "kvm/util.h" -#include "kvm/kvm.h" -#include "kvm/pci.h" -#include "kvm/threadpool.h" -#include "kvm/irq.h" -#include "kvm/ioeventfd.h" - -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <pthread.h> -#include <dirent.h> - -#include <linux/virtio_ring.h> -#include <linux/virtio_9p.h> -#include <net/9p/9p.h> - -#define NUM_VIRT_QUEUES 1 -#define VIRTQUEUE_NUM 128 -#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; - u8 cmd; - u16 tag; - u8 msg[0]; -} __attribute__((packed)); - -struct p9_fid { - u32 fid; - u8 is_dir; - char abs_path[PATH_MAX]; - char *path; - DIR *dir; - int fd; -}; - -struct p9_dev_job { - struct virt_queue *vq; - struct p9_dev *p9dev; - void *job_id; -}; - -struct p9_dev { - u8 status; - u8 isr; - u16 config_vector; - u32 features; - struct virtio_9p_config *config; - u16 base_addr; - - /* virtio queue */ - u16 queue_selector; - struct virt_queue vqs[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; -}; -struct p9_pdu { - u32 queue_head; - int offset; - u16 out_iov_cnt; - u16 in_iov_cnt; - struct iovec in_iov[VIRTQUEUE_NUM]; - struct iovec out_iov[VIRTQUEUE_NUM]; -}; +#include <net/9p/9p.h> /* Warning: Immediately use value returned from this function */ static const char *rel_to_abs(struct p9_dev *p9dev, @@ -185,13 +110,16 @@ static void close_fid(struct p9_dev *p9dev, u32 fid) } } -static void set_p9msg_hdr(struct p9_msg *msg, u32 size, u8 cmd, u16 tag) +static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size) { - *msg = (struct p9_msg) { - .size = size, - .tag = tag, - .cmd = cmd, - }; + u8 cmd; + u16 tag; + + pdu->read_offset = sizeof(u32); + virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag); + pdu->write_offset = 0; + /* cmd + 1 is the reply message */ + virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag); } static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) @@ -213,67 +141,61 @@ static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) static void virtio_p9_error_reply(struct p9_dev *p9dev, struct p9_pdu *pdu, int err, u32 *outlen) { + u16 tag; char *err_str; - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; - struct p9_rerror *rerror = (struct p9_rerror *)inmsg->msg; err_str = strerror(err); - rerror->error.len = strlen(err_str); - memcpy(&rerror->error.str, err_str, rerror->error.len); + pdu->write_offset = VIRTIO_P9_HDR_LEN; + virtio_p9_pdu_writef(pdu, "s", err_str); + *outlen = pdu->write_offset; + + pdu->read_offset = sizeof(u32) + sizeof(u8); + virtio_p9_pdu_readf(pdu, "w", &tag); - *outlen = VIRTIO_P9_HDR_LEN + rerror->error.len + sizeof(u16); - set_p9msg_hdr(inmsg, *outlen, P9_RERROR, outmsg->tag); + pdu->write_offset = 0; + virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RERROR, tag); } static void virtio_p9_version(struct p9_dev *p9dev, struct p9_pdu *pdu, u32 *outlen) { - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; - struct p9_rversion *rversion = (struct p9_rversion *)inmsg->msg; - - rversion->msize = 4096; - 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); - set_p9msg_hdr(inmsg, *outlen, P9_RVERSION, outmsg->tag); + virtio_p9_pdu_writef(pdu, "ds", 4096, VIRTIO_P9_VERSION); + *outlen = pdu->write_offset; + virtio_p9_set_reply_header(pdu, *outlen); return; } static void virtio_p9_clunk(struct p9_dev *p9dev, struct p9_pdu *pdu, u32 *outlen) { - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; - struct p9_tclunk *tclunk = (struct p9_tclunk *)outmsg->msg; - - close_fid(p9dev, tclunk->fid); + u32 fid; - *outlen = VIRTIO_P9_HDR_LEN; - set_p9msg_hdr(inmsg, *outlen, P9_RCLUNK, outmsg->tag); + virtio_p9_pdu_readf(pdu, "d", &fid); + close_fid(p9dev, fid); + *outlen = pdu->write_offset; + virtio_p9_set_reply_header(pdu, *outlen); return; } static void virtio_p9_open(struct p9_dev *p9dev, struct p9_pdu *pdu, u32 *outlen) { + u8 mode; + u32 fid; struct stat st; - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; - struct p9_topen *topen = (struct p9_topen *)outmsg->msg; - struct p9_ropen *ropen = (struct p9_ropen *)inmsg->msg; - struct p9_fid *new_fid = &p9dev->fids[topen->fid]; + struct p9_qid qid; + struct p9_fid *new_fid; + + + virtio_p9_pdu_readf(pdu, "db", &fid, &mode); + new_fid = &p9dev->fids[fid]; if (lstat(new_fid->abs_path, &st) < 0) goto err_out; - st2qid(&st, &ropen->qid); - ropen->iounit = 0; + st2qid(&st, &qid); if (new_fid->is_dir) { new_fid->dir = opendir(new_fid->abs_path); @@ -281,12 +203,14 @@ static void virtio_p9_open(struct p9_dev *p9dev, goto err_out; } else { new_fid->fd = open(new_fid->abs_path, - omode2uflags(topen->mode) | O_NOFOLLOW); + omode2uflags(mode) | O_NOFOLLOW); if (new_fid->fd < 0) goto err_out; } - *outlen = VIRTIO_P9_HDR_LEN + sizeof(*ropen); - set_p9msg_hdr(inmsg, *outlen, P9_ROPEN, outmsg->tag); + virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); + + *outlen = pdu->write_offset; + virtio_p9_set_reply_header(pdu, *outlen); return; err_out: virtio_p9_error_reply(p9dev, pdu, errno, outlen); @@ -298,39 +222,33 @@ static void virtio_p9_create(struct p9_dev *p9dev, { u8 mode; u32 perm; + char *name; + u32 fid_val; struct stat st; - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; - struct p9_tcreate *tcreate = (struct p9_tcreate *)outmsg->msg; - struct p9_rcreate *rcreate = (struct p9_rcreate *)inmsg->msg; - struct p9_fid *fid = &p9dev->fids[tcreate->fid]; - - - rcreate->iounit = 0; - - /* Get last byte of the variable length struct */ - mode = *((u8 *)outmsg + outmsg->size - 1); - perm = *(u32 *)((u8 *)outmsg + outmsg->size - 5); + struct p9_qid qid; + struct p9_fid *fid; - sprintf(fid->path, "%s/%.*s", fid->path, tcreate->name.len, (char *)&tcreate->name.str); + virtio_p9_pdu_readf(pdu, "dsdb", &fid_val, &name, &perm, &mode); + fid = &p9dev->fids[fid_val]; - close_fid(p9dev, tcreate->fid); + sprintf(fid->path, "%s/%.*s", fid->path, (int)strlen(name), name); + close_fid(p9dev, fid_val); if (perm & P9_DMDIR) { mkdir(fid->abs_path, perm & 0xFFFF); fid->dir = opendir(fid->abs_path); fid->is_dir = 1; } else { - fid->fd = open(fid->abs_path, omode2uflags(mode) | O_CREAT, 0777); + fid->fd = open(fid->abs_path, + omode2uflags(mode) | O_CREAT, 0777); } - if (lstat(fid->abs_path, &st) < 0) goto err_out; - st2qid(&st, &rcreate->qid); - - *outlen = VIRTIO_P9_HDR_LEN + sizeof(*rcreate); - set_p9msg_hdr(inmsg, *outlen, P9_RCREATE, outmsg->tag); + st2qid(&st, &qid); + virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); + *outlen = pdu->write_offset; + virtio_p9_set_reply_header(pdu, *outlen); return; err_out: virtio_p9_error_reply(p9dev, pdu, errno, outlen); @@ -341,45 +259,57 @@ static void virtio_p9_walk(struct p9_dev *p9dev, struct p9_pdu *pdu, u32 *outlen) { u8 i; - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; - struct p9_twalk *twalk = (struct p9_twalk *)outmsg->msg; - struct p9_rwalk *rwalk = (struct p9_rwalk *)inmsg->msg; - struct p9_str *str = twalk->wnames; - struct p9_fid *new_fid = &p9dev->fids[twalk->newfid]; + u16 nwqid; + char *str; + u16 nwname; + u32 fid_val; + u32 newfid_val; + struct p9_qid wqid; + struct p9_fid *new_fid; + + virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname); + new_fid = &p9dev->fids[newfid_val]; - rwalk->nwqid = 0; - if (twalk->nwname) { - struct p9_fid *fid = &p9dev->fids[twalk->fid]; + nwqid = 0; + if (nwname) { + struct p9_fid *fid = &p9dev->fids[fid_val]; - for (i = 0; i < twalk->nwname; i++) { + /* skip the space for count */ + pdu->write_offset += sizeof(u16); + for (i = 0; i < nwname; i++) { + struct stat st; char tmp[PATH_MAX] = {0}; char full_path[PATH_MAX]; - struct stat st; - /* Format the new path we're 'walk'ing into */ - sprintf(tmp, "%s/%.*s", fid->path, - str->len, (char *)&str->str); + virtio_p9_pdu_readf(pdu, "s", &str); + /* Format the new path we're 'walk'ing into */ + sprintf(tmp, "%s/%.*s", + fid->path, (int)strlen(str), str); if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0) goto err_out; - st2qid(&st, &rwalk->wqids[i]); + st2qid(&st, &wqid); new_fid->is_dir = S_ISDIR(st.st_mode); strcpy(new_fid->path, tmp); - new_fid->fid = twalk->newfid; - rwalk->nwqid++; + new_fid->fid = newfid_val; + nwqid++; + virtio_p9_pdu_writef(pdu, "Q", &wqid); } } else { - new_fid->is_dir = p9dev->fids[twalk->fid].is_dir; - strcpy(new_fid->path, p9dev->fids[twalk->fid].path); - new_fid->fid = twalk->newfid; + /* + * update write_offset so our outlen get correct value + */ + pdu->write_offset += sizeof(u16); + new_fid->is_dir = p9dev->fids[fid_val].is_dir; + strcpy(new_fid->path, p9dev->fids[fid_val].path); + new_fid->fid = newfid_val; } - - *outlen = VIRTIO_P9_HDR_LEN + sizeof(u16) + - sizeof(struct p9_qid)*rwalk->nwqid; - set_p9msg_hdr(inmsg, *outlen, P9_RWALK, outmsg->tag); + *outlen = pdu->write_offset; + pdu->write_offset = VIRTIO_P9_HDR_LEN; + virtio_p9_pdu_writef(pdu, "d", nwqid); + virtio_p9_set_reply_header(pdu, *outlen); return; err_out: virtio_p9_error_reply(p9dev, pdu, errno, outlen); @@ -390,12 +320,15 @@ static void virtio_p9_attach(struct p9_dev *p9dev, struct p9_pdu *pdu, u32 *outlen) { u32 i; + u32 fid_val; + u32 afid; + char *uname; + char *aname; struct stat st; + struct p9_qid qid; struct p9_fid *fid; - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; - struct p9_rattach *rattach = (struct p9_rattach *)inmsg->msg; - struct p9_tattach *tattach = (struct p9_tattach *)outmsg->msg; + + virtio_p9_pdu_readf(pdu, "ddss", &fid_val, &afid, &uname, &aname); /* Reset everything */ for (i = 0; i < VIRTIO_P9_MAX_FID; i++) @@ -404,103 +337,106 @@ static void virtio_p9_attach(struct p9_dev *p9dev, if (lstat(p9dev->root_dir, &st) < 0) goto err_out; - st2qid(&st, &rattach->qid); + st2qid(&st, &qid); - fid = &p9dev->fids[tattach->fid]; - fid->fid = tattach->fid; + fid = &p9dev->fids[fid_val]; + fid->fid = fid_val; fid->is_dir = 1; strcpy(fid->path, "/"); - *outlen = VIRTIO_P9_HDR_LEN + sizeof(*rattach); - set_p9msg_hdr(inmsg, *outlen, P9_RATTACH, outmsg->tag); + virtio_p9_pdu_writef(pdu, "Q", &qid); + *outlen = pdu->write_offset; + virtio_p9_set_reply_header(pdu, *outlen); return; err_out: virtio_p9_error_reply(p9dev, pdu, errno, outlen); return; } -static u32 virtio_p9_fill_stat(struct p9_dev *p9dev, const char *name, - struct stat *st, struct p9_rstat *rstat) +static void virtio_p9_fill_stat(struct p9_dev *p9dev, const char *name, + struct stat *st, struct p9_wstat *wstat) { - struct p9_str *str; - - rstat->stat.type = 0; - rstat->stat.dev = 0; - st2qid(st, &rstat->stat.qid); - rstat->stat.mode = st->st_mode; - rstat->stat.length = st->st_size; + wstat->type = 0; + wstat->dev = 0; + st2qid(st, &wstat->qid); + wstat->mode = st->st_mode; + wstat->length = st->st_size; if (S_ISDIR(st->st_mode)) { - rstat->stat.length = 0; - rstat->stat.mode |= P9_DMDIR; + wstat->length = 0; + wstat->mode |= P9_DMDIR; } - rstat->stat.atime = st->st_atime; - rstat->stat.mtime = st->st_mtime; - - str = (struct p9_str *)&rstat->stat.name; - str->len = strlen(name); - memcpy(&str->str, name, str->len); - str = (void *)str + str->len + sizeof(u16); - - /* TODO: Pass usernames to the client */ - str->len = 0; - str = (void *)str + sizeof(u16); - str->len = 0; - str = (void *)str + sizeof(u16); - str->len = 0; - str = (void *)str + sizeof(u16); - - /* - * 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); + wstat->atime = st->st_atime; + wstat->mtime = st->st_mtime; + + wstat->name = strdup(name); + wstat->uid = NULL; + wstat->gid = NULL; + wstat->muid = NULL; + + /* NOTE: size shouldn't include its own length */ + /* size[2] type[2] dev[4] qid[13] */ + /* mode[4] atime[4] mtime[4] length[8]*/ + /* name[s] uid[s] gid[s] muid[s] */ + wstat->size = 2+4+13+4+4+4+8+2+2+2+2; + if (wstat->name) + wstat->size += strlen(wstat->name); } static void virtio_p9_read(struct p9_dev *p9dev, struct p9_pdu *pdu, u32 *outlen) { - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; - struct p9_tread *tread = (struct p9_tread *)outmsg->msg; - struct p9_rread *rread = (struct p9_rread *)inmsg->msg; - struct p9_rstat *rstat = (struct p9_rstat *)pdu->in_iov[1].iov_base; - struct p9_fid *fid = &p9dev->fids[tread->fid]; + u64 offset; + u32 fid_val; + u32 count, rcount; struct stat st; + struct p9_fid *fid; + struct p9_wstat wstat; - rread->count = 0; - + rcount = 0; + virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); + fid = &p9dev->fids[fid_val]; if (fid->is_dir) { /* If reading a dir, fill the buffer with p9_stat entries */ - struct dirent *cur = readdir(fid->dir); char full_path[PATH_MAX]; + struct dirent *cur = readdir(fid->dir); + /* Skip the space for writing count */ + pdu->write_offset += sizeof(u32); while (cur) { u32 read; lstat(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; + virtio_p9_fill_stat(p9dev, cur->d_name, &st, &wstat); + + read = pdu->write_offset; + virtio_p9_pdu_writef(pdu, "S", &wstat); + rcount += pdu->write_offset - read; + cur = readdir(fid->dir); } } else { pdu->in_iov[0].iov_base += VIRTIO_P9_HDR_LEN + sizeof(u32); pdu->in_iov[0].iov_len -= VIRTIO_P9_HDR_LEN + sizeof(u32); pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov, - tread->count, - pdu->in_iov_cnt); - rread->count = preadv(fid->fd, pdu->in_iov, - pdu->in_iov_cnt, tread->offset); - if (rread->count > tread->count) - rread->count = tread->count; - } + count, + pdu->in_iov_cnt); + rcount = preadv(fid->fd, pdu->in_iov, + pdu->in_iov_cnt, offset); + if (rcount > count) + rcount = count; + /* + * Update the iov_base back, so that rest of + * pdu_writef works correctly. + */ + pdu->in_iov[0].iov_base -= VIRTIO_P9_HDR_LEN + sizeof(u32); + pdu->in_iov[0].iov_len += VIRTIO_P9_HDR_LEN + sizeof(u32); - *outlen = VIRTIO_P9_HDR_LEN + sizeof(u32) + rread->count; - set_p9msg_hdr(inmsg, *outlen, P9_RREAD, outmsg->tag); + } + pdu->write_offset = VIRTIO_P9_HDR_LEN; + virtio_p9_pdu_writef(pdu, "d", rcount); + *outlen = pdu->write_offset + rcount; + virtio_p9_set_reply_header(pdu, *outlen); return; } @@ -508,21 +444,21 @@ static void virtio_p9_read(struct p9_dev *p9dev, static void virtio_p9_stat(struct p9_dev *p9dev, struct p9_pdu *pdu, u32 *outlen) { - u32 ret; + u32 fid_val; struct stat st; - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; - struct p9_tstat *tstat = (struct p9_tstat *)outmsg->msg; - struct p9_rstat *rstat = (struct p9_rstat *)(inmsg->msg + sizeof(u16)); - struct p9_fid *fid = &p9dev->fids[tstat->fid]; + struct p9_fid *fid; + struct p9_wstat wstat; + virtio_p9_pdu_readf(pdu, "d", &fid_val); + fid = &p9dev->fids[fid_val]; if (lstat(fid->abs_path, &st) < 0) goto err_out; - ret = virtio_p9_fill_stat(p9dev, fid->path, &st, rstat); + virtio_p9_fill_stat(p9dev, fid->path, &st, &wstat); - *outlen = VIRTIO_P9_HDR_LEN + ret + sizeof(u16); - set_p9msg_hdr(inmsg, *outlen, P9_RSTAT, outmsg->tag); + virtio_p9_pdu_writef(pdu, "wS", 0, &wstat); + *outlen = pdu->write_offset; + virtio_p9_set_reply_header(pdu, *outlen); return; err_out: virtio_p9_error_reply(p9dev, pdu, errno, outlen); @@ -533,21 +469,21 @@ static void virtio_p9_wstat(struct p9_dev *p9dev, struct p9_pdu *pdu, u32 *outlen) { int res = 0; - struct p9_str *str; - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; - struct p9_twstat *twstat = (struct p9_twstat *)outmsg->msg; - struct p9_fid *fid = &p9dev->fids[twstat->fid]; + u32 fid_val; + u16 unused; + struct p9_fid *fid; + struct p9_wstat wstat; + virtio_p9_pdu_readf(pdu, "dwS", &fid_val, &unused, &wstat); + fid = &p9dev->fids[fid_val]; - if (twstat->stat.length != -1UL) - res = ftruncate(fid->fd, twstat->stat.length); + if (wstat.length != -1UL) + res = ftruncate(fid->fd, wstat.length); - if (twstat->stat.mode != -1U) - chmod(fid->abs_path, twstat->stat.mode & 0xFFFF); + if (wstat.mode != -1U) + chmod(fid->abs_path, wstat.mode & 0xFFFF); - str = (void *)&twstat->stat.name + sizeof(u16); - if (str->len > 0) { + if (strlen(wstat.name) > 0) { char new_name[PATH_MAX] = {0}; char full_path[PATH_MAX]; char *last_dir = strrchr(fid->path, '/'); @@ -556,57 +492,59 @@ static void virtio_p9_wstat(struct p9_dev *p9dev, if (last_dir) strncpy(new_name, fid->path, last_dir - fid->path + 1); - memcpy(new_name + strlen(new_name), &str->str, str->len); + memcpy(new_name + strlen(new_name), + wstat.name, strlen(wstat.name)); /* fid is reused for the new file */ rename(fid->abs_path, rel_to_abs(p9dev, new_name, full_path)); sprintf(fid->path, "%s", new_name); } - *outlen = VIRTIO_P9_HDR_LEN; - set_p9msg_hdr(inmsg, *outlen, P9_RWSTAT, outmsg->tag); - + virtio_p9_set_reply_header(pdu, *outlen); return; } static void virtio_p9_remove(struct p9_dev *p9dev, struct p9_pdu *pdu, u32 *outlen) { - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; - struct p9_tremove *tremove = (struct p9_tremove *)outmsg->msg; - struct p9_fid *fid = &p9dev->fids[tremove->fid]; + u32 fid_val; + struct p9_fid *fid; - close_fid(p9dev, tremove->fid); + virtio_p9_pdu_readf(pdu, "d", &fid_val); + fid = &p9dev->fids[fid_val]; + close_fid(p9dev, fid_val); if (fid->is_dir) rmdir(fid->abs_path); else unlink(fid->abs_path); *outlen = VIRTIO_P9_HDR_LEN; - set_p9msg_hdr(inmsg, *outlen, P9_RREMOVE, outmsg->tag); + virtio_p9_set_reply_header(pdu, *outlen); return; } static void virtio_p9_write(struct p9_dev *p9dev, struct p9_pdu *pdu, u32 *outlen) { - struct p9_msg *inmsg = pdu->in_iov[0].iov_base; - struct p9_msg *outmsg = pdu->out_iov[0].iov_base; - struct p9_twrite *twrite = (struct p9_twrite *)outmsg->msg; - struct p9_rwrite *rwrite = (struct p9_rwrite *)inmsg->msg; - struct p9_fid *fid = &p9dev->fids[twrite->fid]; + u64 offset; + u32 fid_val; + u32 count, rcount; + struct p9_fid *fid; + virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); + fid = &p9dev->fids[fid_val]; - pdu->out_iov[0].iov_base += (sizeof(*outmsg) + sizeof(*twrite)); - pdu->out_iov[0].iov_len -= (sizeof(*outmsg) + sizeof(*twrite)); - pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, twrite->count, + /* Adjust the iovec to skip the header and meta data */ + pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + + sizeof(struct p9_twrite)); + pdu->out_iov[0].iov_len -= (sizeof(struct p9_msg) + + sizeof(struct p9_twrite)); + pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count, pdu->out_iov_cnt); - rwrite->count = pwritev(fid->fd, pdu->out_iov, - pdu->out_iov_cnt, twrite->offset); - *outlen = VIRTIO_P9_HDR_LEN + sizeof(u32); - set_p9msg_hdr(inmsg, *outlen, P9_RWRITE, outmsg->tag); - + rcount = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset); + virtio_p9_pdu_writef(pdu, "d", rcount); + *outlen = pdu->write_offset; + virtio_p9_set_reply_header(pdu, *outlen); return; } @@ -633,6 +571,9 @@ static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq) if (!pdu) return NULL; + /* skip the pdu header p9_msg */ + pdu->read_offset = VIRTIO_P9_HDR_LEN; + pdu->write_offset = VIRTIO_P9_HDR_LEN; pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov, pdu->out_iov, &pdu->in_iov_cnt,
The protocol data is in little-endian format. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> --- tools/kvm/Makefile | 1 + tools/kvm/include/kvm/virtio-9p.h | 80 ++++++- tools/kvm/virtio/9p-pdu.c | 239 ++++++++++++++++++ tools/kvm/virtio/9p.c | 479 ++++++++++++++++--------------------- 4 files changed, 529 insertions(+), 270 deletions(-) create mode 100644 tools/kvm/virtio/9p-pdu.c