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 <[email protected]>

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,

-- 

Sasha.

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to