mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-09-01 02:34:45 +00:00
tools/kvm/9p: Add encode/decode routines for protocol data
The protocol data is in little-endian format. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
committed by
Will Deacon
parent
b4fdde6d2f
commit
bfc152686a
@@ -65,6 +65,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
|
||||
|
||||
|
||||
+65
-1
@@ -1,8 +1,72 @@
|
||||
#ifndef KVM__VIRTIO_9P_H
|
||||
#define KVM__VIRTIO_9P_H
|
||||
#include "kvm/virtio.h"
|
||||
#include "kvm/pci.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.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
|
||||
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
#include "kvm/util.h"
|
||||
#include "kvm/virtio-9p.h"
|
||||
|
||||
#include <endian.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <linux/compiler.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;
|
||||
}
|
||||
+214
-256
@@ -1,81 +1,23 @@
|
||||
#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 "kvm/irq.h"
|
||||
#include "kvm/virtio-9p.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pthread.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.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];
|
||||
};
|
||||
|
||||
/* Warning: Immediately use value returned from this function */
|
||||
static const char *rel_to_abs(struct p9_dev *p9dev,
|
||||
@@ -185,13 +127,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 +158,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;
|
||||
|
||||
*outlen = VIRTIO_P9_HDR_LEN + rerror->error.len + sizeof(u16);
|
||||
set_p9msg_hdr(inmsg, *outlen, P9_RERROR, outmsg->tag);
|
||||
pdu->read_offset = sizeof(u32) + sizeof(u8);
|
||||
virtio_p9_pdu_readf(pdu, "w", &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;
|
||||
u32 fid;
|
||||
|
||||
close_fid(p9dev, tclunk->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 +220,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 +239,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];
|
||||
struct p9_qid qid;
|
||||
struct p9_fid *fid;
|
||||
|
||||
virtio_p9_pdu_readf(pdu, "dsdb", &fid_val, &name, &perm, &mode);
|
||||
fid = &p9dev->fids[fid_val];
|
||||
|
||||
rcreate->iounit = 0;
|
||||
|
||||
/* Get last byte of the variable length struct */
|
||||
mode = *((u8 *)outmsg + outmsg->size - 1);
|
||||
perm = *(u32 *)((u8 *)outmsg + outmsg->size - 5);
|
||||
|
||||
sprintf(fid->path, "%s/%.*s", fid->path, tcreate->name.len, (char *)&tcreate->name.str);
|
||||
|
||||
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 +276,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;
|
||||
|
||||
|
||||
rwalk->nwqid = 0;
|
||||
if (twalk->nwname) {
|
||||
struct p9_fid *fid = &p9dev->fids[twalk->fid];
|
||||
virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname);
|
||||
new_fid = &p9dev->fids[newfid_val];
|
||||
|
||||
for (i = 0; i < twalk->nwname; i++) {
|
||||
nwqid = 0;
|
||||
if (nwname) {
|
||||
struct p9_fid *fid = &p9dev->fids[fid_val];
|
||||
|
||||
/* 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;
|
||||
|
||||
virtio_p9_pdu_readf(pdu, "s", &str);
|
||||
|
||||
/* Format the new path we're 'walk'ing into */
|
||||
sprintf(tmp, "%s/%.*s", fid->path,
|
||||
str->len, (char *)&str->str);
|
||||
|
||||
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 +337,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 +354,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;
|
||||
wstat->atime = st->st_atime;
|
||||
wstat->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);
|
||||
wstat->name = strdup(name);
|
||||
wstat->uid = NULL;
|
||||
wstat->gid = NULL;
|
||||
wstat->muid = NULL;
|
||||
|
||||
/* 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);
|
||||
/* 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 +461,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 +486,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 +509,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 +588,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,
|
||||
|
||||
Reference in New Issue
Block a user