- fixes a minor bug that could possibly prevent old guests to remove
directories - makes default permissions for new files configurable from the cmdline when using mapped security modes - handle transport errors - g_malloc()+memcpy() converted to g_memdup() -----BEGIN PGP SIGNATURE----- iEYEABECAAYFAllU/MoACgkQAvw66wEB28LAmACdF6N92+HJvgITnPH8BDWj/vFL OCsAn3ETBKXg0mOz2janivLtgR4ycFOw =8s75 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/gkurz/tags/for-upstream' into staging - fixes a minor bug that could possibly prevent old guests to remove directories - makes default permissions for new files configurable from the cmdline when using mapped security modes - handle transport errors - g_malloc()+memcpy() converted to g_memdup() # gpg: Signature made Thu 29 Jun 2017 14:12:42 BST # gpg: using DSA key 0x02FC3AEB0101DBC2 # gpg: Good signature from "Greg Kurz <groug@kaod.org>" # gpg: aka "Greg Kurz <groug@free.fr>" # gpg: aka "Greg Kurz <gkurz@linux.vnet.ibm.com>" # gpg: aka "Gregory Kurz (Groug) <groug@free.fr>" # gpg: aka "[jpeg image of size 3330]" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 2BD4 3B44 535E C0A7 9894 DBA2 02FC 3AEB 0101 DBC2 * remotes/gkurz/tags/for-upstream: 9pfs: handle transport errors in pdu_complete() xen-9pfs: disconnect if buffers are misconfigured virtio-9p: break device if buffers are misconfigured virtio-9p: message header is 7-byte long virtio-9p: record element after sanity checks 9pfs: replace g_malloc()+memcpy() with g_memdup() 9pfs: local: Add support for custom fmode/dmode in 9ps mapped security modes 9pfs: local: remove: use correct path component Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
454d7dc9bc
|
@ -76,6 +76,8 @@ typedef struct FsDriverEntry {
|
||||||
int export_flags;
|
int export_flags;
|
||||||
FileOperations *ops;
|
FileOperations *ops;
|
||||||
FsThrottle fst;
|
FsThrottle fst;
|
||||||
|
mode_t fmode;
|
||||||
|
mode_t dmode;
|
||||||
} FsDriverEntry;
|
} FsDriverEntry;
|
||||||
|
|
||||||
typedef struct FsContext
|
typedef struct FsContext
|
||||||
|
@ -88,6 +90,8 @@ typedef struct FsContext
|
||||||
FsThrottle *fst;
|
FsThrottle *fst;
|
||||||
/* fs driver specific data */
|
/* fs driver specific data */
|
||||||
void *private;
|
void *private;
|
||||||
|
mode_t fmode;
|
||||||
|
mode_t dmode;
|
||||||
} FsContext;
|
} FsContext;
|
||||||
|
|
||||||
typedef struct V9fsPath {
|
typedef struct V9fsPath {
|
||||||
|
|
|
@ -38,6 +38,12 @@ static QemuOptsList qemu_fsdev_opts = {
|
||||||
}, {
|
}, {
|
||||||
.name = "sock_fd",
|
.name = "sock_fd",
|
||||||
.type = QEMU_OPT_NUMBER,
|
.type = QEMU_OPT_NUMBER,
|
||||||
|
}, {
|
||||||
|
.name = "fmode",
|
||||||
|
.type = QEMU_OPT_NUMBER,
|
||||||
|
}, {
|
||||||
|
.name = "dmode",
|
||||||
|
.type = QEMU_OPT_NUMBER,
|
||||||
},
|
},
|
||||||
|
|
||||||
THROTTLE_OPTS,
|
THROTTLE_OPTS,
|
||||||
|
@ -75,6 +81,12 @@ static QemuOptsList qemu_virtfs_opts = {
|
||||||
}, {
|
}, {
|
||||||
.name = "sock_fd",
|
.name = "sock_fd",
|
||||||
.type = QEMU_OPT_NUMBER,
|
.type = QEMU_OPT_NUMBER,
|
||||||
|
}, {
|
||||||
|
.name = "fmode",
|
||||||
|
.type = QEMU_OPT_NUMBER,
|
||||||
|
}, {
|
||||||
|
.name = "dmode",
|
||||||
|
.type = QEMU_OPT_NUMBER,
|
||||||
},
|
},
|
||||||
|
|
||||||
{ /*End of list */ }
|
{ /*End of list */ }
|
||||||
|
|
|
@ -633,7 +633,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
|
||||||
|
|
||||||
if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
|
if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
|
||||||
fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
err = mknodat(dirfd, name, SM_LOCAL_MODE_BITS | S_IFREG, 0);
|
err = mknodat(dirfd, name, fs_ctx->fmode | S_IFREG, 0);
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -685,7 +685,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
|
||||||
|
|
||||||
if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
|
if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
|
||||||
fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
err = mkdirat(dirfd, name, SM_LOCAL_DIR_MODE_BITS);
|
err = mkdirat(dirfd, name, fs_ctx->dmode);
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -786,7 +786,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
|
||||||
/* Determine the security model */
|
/* Determine the security model */
|
||||||
if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
|
if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
|
||||||
fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
fd = openat_file(dirfd, name, flags, SM_LOCAL_MODE_BITS);
|
fd = openat_file(dirfd, name, flags, fs_ctx->fmode);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -849,7 +849,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
|
||||||
ssize_t oldpath_size, write_size;
|
ssize_t oldpath_size, write_size;
|
||||||
|
|
||||||
fd = openat_file(dirfd, name, O_CREAT | O_EXCL | O_RDWR,
|
fd = openat_file(dirfd, name, O_CREAT | O_EXCL | O_RDWR,
|
||||||
SM_LOCAL_MODE_BITS);
|
fs_ctx->fmode);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1100,7 +1100,7 @@ static int local_remove(FsContext *ctx, const char *path)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fstatat(dirfd, path, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) {
|
if (fstatat(dirfd, name, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) {
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1467,6 +1467,23 @@ static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fse->export_flags & V9FS_SM_MAPPED ||
|
||||||
|
fse->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
fse->fmode =
|
||||||
|
qemu_opt_get_number(opts, "fmode", SM_LOCAL_MODE_BITS) & 0777;
|
||||||
|
fse->dmode =
|
||||||
|
qemu_opt_get_number(opts, "dmode", SM_LOCAL_DIR_MODE_BITS) & 0777;
|
||||||
|
} else {
|
||||||
|
if (qemu_opt_find(opts, "fmode")) {
|
||||||
|
error_report("fmode is only valid for mapped 9p modes");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (qemu_opt_find(opts, "dmode")) {
|
||||||
|
error_report("dmode is only valid for mapped 9p modes");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fse->path = g_strdup(path);
|
fse->path = g_strdup(path);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -494,8 +494,7 @@ static int synth_name_to_path(FsContext *ctx, V9fsPath *dir_path,
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
/* Copy the node pointer to fid */
|
/* Copy the node pointer to fid */
|
||||||
target->data = g_malloc(sizeof(void *));
|
target->data = g_memdup(&node, sizeof(void *));
|
||||||
memcpy(target->data, &node, sizeof(void *));
|
|
||||||
target->size = sizeof(void *);
|
target->size = sizeof(void *);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
28
hw/9pfs/9p.c
28
hw/9pfs/9p.c
|
@ -624,15 +624,11 @@ void pdu_free(V9fsPDU *pdu)
|
||||||
QLIST_INSERT_HEAD(&s->free_list, pdu, next);
|
QLIST_INSERT_HEAD(&s->free_list, pdu, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We don't do error checking for pdu_marshal/unmarshal here
|
|
||||||
* because we always expect to have enough space to encode
|
|
||||||
* error details
|
|
||||||
*/
|
|
||||||
static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len)
|
static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len)
|
||||||
{
|
{
|
||||||
int8_t id = pdu->id + 1; /* Response */
|
int8_t id = pdu->id + 1; /* Response */
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
int err = -len;
|
int err = -len;
|
||||||
|
@ -644,11 +640,19 @@ static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len)
|
||||||
str.data = strerror(err);
|
str.data = strerror(err);
|
||||||
str.size = strlen(str.data);
|
str.size = strlen(str.data);
|
||||||
|
|
||||||
len += pdu_marshal(pdu, len, "s", &str);
|
ret = pdu_marshal(pdu, len, "s", &str);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out_notify;
|
||||||
|
}
|
||||||
|
len += ret;
|
||||||
id = P9_RERROR;
|
id = P9_RERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
len += pdu_marshal(pdu, len, "d", err);
|
ret = pdu_marshal(pdu, len, "d", err);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out_notify;
|
||||||
|
}
|
||||||
|
len += ret;
|
||||||
|
|
||||||
if (s->proto_version == V9FS_PROTO_2000L) {
|
if (s->proto_version == V9FS_PROTO_2000L) {
|
||||||
id = P9_RLERROR;
|
id = P9_RLERROR;
|
||||||
|
@ -657,12 +661,15 @@ static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fill out the header */
|
/* fill out the header */
|
||||||
pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
|
if (pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag) < 0) {
|
||||||
|
goto out_notify;
|
||||||
|
}
|
||||||
|
|
||||||
/* keep these in sync */
|
/* keep these in sync */
|
||||||
pdu->size = len;
|
pdu->size = len;
|
||||||
pdu->id = id;
|
pdu->id = id;
|
||||||
|
|
||||||
|
out_notify:
|
||||||
pdu->s->transport->push_and_notify(pdu);
|
pdu->s->transport->push_and_notify(pdu);
|
||||||
|
|
||||||
/* Now wakeup anybody waiting in flush for this request */
|
/* Now wakeup anybody waiting in flush for this request */
|
||||||
|
@ -1664,7 +1671,7 @@ static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
|
||||||
unsigned int niov;
|
unsigned int niov;
|
||||||
|
|
||||||
if (is_write) {
|
if (is_write) {
|
||||||
pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov);
|
pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov, size + skip);
|
||||||
} else {
|
} else {
|
||||||
pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size + skip);
|
pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size + skip);
|
||||||
}
|
}
|
||||||
|
@ -3533,6 +3540,9 @@ int v9fs_device_realize_common(V9fsState *s, Error **errp)
|
||||||
|
|
||||||
s->ops = fse->ops;
|
s->ops = fse->ops;
|
||||||
|
|
||||||
|
s->ctx.fmode = fse->fmode;
|
||||||
|
s->ctx.dmode = fse->dmode;
|
||||||
|
|
||||||
s->fid_list = NULL;
|
s->fid_list = NULL;
|
||||||
qemu_co_rwlock_init(&s->rename_lock);
|
qemu_co_rwlock_init(&s->rename_lock);
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,11 @@ typedef struct {
|
||||||
uint8_t id;
|
uint8_t id;
|
||||||
uint16_t tag_le;
|
uint16_t tag_le;
|
||||||
} QEMU_PACKED P9MsgHeader;
|
} QEMU_PACKED P9MsgHeader;
|
||||||
|
/* According to the specification, 9p messages start with a 7-byte header.
|
||||||
|
* Since most of the code uses this header size in literal form, we must be
|
||||||
|
* sure this is indeed the case.
|
||||||
|
*/
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(P9MsgHeader) != 7);
|
||||||
|
|
||||||
struct V9fsPDU
|
struct V9fsPDU
|
||||||
{
|
{
|
||||||
|
@ -358,7 +363,7 @@ struct V9fsTransport {
|
||||||
void (*init_in_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov,
|
void (*init_in_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov,
|
||||||
unsigned int *pniov, size_t size);
|
unsigned int *pniov, size_t size);
|
||||||
void (*init_out_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov,
|
void (*init_out_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov,
|
||||||
unsigned int *pniov);
|
unsigned int *pniov, size_t size);
|
||||||
void (*push_and_notify)(V9fsPDU *pdu);
|
void (*push_and_notify)(V9fsPDU *pdu);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,23 +53,22 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
goto out_free_pdu;
|
goto out_free_pdu;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elem->in_num == 0) {
|
if (iov_size(elem->in_sg, elem->in_num) < 7) {
|
||||||
virtio_error(vdev,
|
virtio_error(vdev,
|
||||||
"The guest sent a VirtFS request without space for "
|
"The guest sent a VirtFS request without space for "
|
||||||
"the reply");
|
"the reply");
|
||||||
goto out_free_req;
|
goto out_free_req;
|
||||||
}
|
}
|
||||||
QEMU_BUILD_BUG_ON(sizeof(out) != 7);
|
|
||||||
|
|
||||||
v->elems[pdu->idx] = elem;
|
len = iov_to_buf(elem->out_sg, elem->out_num, 0, &out, 7);
|
||||||
len = iov_to_buf(elem->out_sg, elem->out_num, 0,
|
if (len != 7) {
|
||||||
&out, sizeof(out));
|
|
||||||
if (len != sizeof(out)) {
|
|
||||||
virtio_error(vdev, "The guest sent a malformed VirtFS request: "
|
virtio_error(vdev, "The guest sent a malformed VirtFS request: "
|
||||||
"header size is %zd, should be 7", len);
|
"header size is %zd, should be 7", len);
|
||||||
goto out_free_req;
|
goto out_free_req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v->elems[pdu->idx] = elem;
|
||||||
|
|
||||||
pdu_submit(pdu, &out);
|
pdu_submit(pdu, &out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,8 +146,16 @@ static ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset,
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||||
VirtQueueElement *elem = v->elems[pdu->idx];
|
VirtQueueElement *elem = v->elems[pdu->idx];
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
return v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap);
|
ret = v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap);
|
||||||
|
if (ret < 0) {
|
||||||
|
VirtIODevice *vdev = VIRTIO_DEVICE(v);
|
||||||
|
|
||||||
|
virtio_error(vdev, "Failed to encode VirtFS reply type %d",
|
||||||
|
pdu->id + 1);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
|
static ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
|
||||||
|
@ -157,28 +164,52 @@ static ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||||
VirtQueueElement *elem = v->elems[pdu->idx];
|
VirtQueueElement *elem = v->elems[pdu->idx];
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
return v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1, fmt, ap);
|
ret = v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1, fmt, ap);
|
||||||
|
if (ret < 0) {
|
||||||
|
VirtIODevice *vdev = VIRTIO_DEVICE(v);
|
||||||
|
|
||||||
|
virtio_error(vdev, "Failed to decode VirtFS request type %d", pdu->id);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The size parameter is used by other transports. Do not drop it. */
|
|
||||||
static void virtio_init_in_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
|
static void virtio_init_in_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
|
||||||
unsigned int *pniov, size_t size)
|
unsigned int *pniov, size_t size)
|
||||||
{
|
{
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||||
VirtQueueElement *elem = v->elems[pdu->idx];
|
VirtQueueElement *elem = v->elems[pdu->idx];
|
||||||
|
size_t buf_size = iov_size(elem->in_sg, elem->in_num);
|
||||||
|
|
||||||
|
if (buf_size < size) {
|
||||||
|
VirtIODevice *vdev = VIRTIO_DEVICE(v);
|
||||||
|
|
||||||
|
virtio_error(vdev,
|
||||||
|
"VirtFS reply type %d needs %zu bytes, buffer has %zu",
|
||||||
|
pdu->id + 1, size, buf_size);
|
||||||
|
}
|
||||||
|
|
||||||
*piov = elem->in_sg;
|
*piov = elem->in_sg;
|
||||||
*pniov = elem->in_num;
|
*pniov = elem->in_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_init_out_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
|
static void virtio_init_out_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
|
||||||
unsigned int *pniov)
|
unsigned int *pniov, size_t size)
|
||||||
{
|
{
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||||
VirtQueueElement *elem = v->elems[pdu->idx];
|
VirtQueueElement *elem = v->elems[pdu->idx];
|
||||||
|
size_t buf_size = iov_size(elem->out_sg, elem->out_num);
|
||||||
|
|
||||||
|
if (buf_size < size) {
|
||||||
|
VirtIODevice *vdev = VIRTIO_DEVICE(v);
|
||||||
|
|
||||||
|
virtio_error(vdev,
|
||||||
|
"VirtFS request type %d needs %zu bytes, buffer has %zu",
|
||||||
|
pdu->id, size, buf_size);
|
||||||
|
}
|
||||||
|
|
||||||
*piov = elem->out_sg;
|
*piov = elem->out_sg;
|
||||||
*pniov = elem->out_num;
|
*pniov = elem->out_num;
|
||||||
|
|
|
@ -54,6 +54,8 @@ typedef struct Xen9pfsDev {
|
||||||
Xen9pfsRing *rings;
|
Xen9pfsRing *rings;
|
||||||
} Xen9pfsDev;
|
} Xen9pfsDev;
|
||||||
|
|
||||||
|
static void xen_9pfs_disconnect(struct XenDevice *xendev);
|
||||||
|
|
||||||
static void xen_9pfs_in_sg(Xen9pfsRing *ring,
|
static void xen_9pfs_in_sg(Xen9pfsRing *ring,
|
||||||
struct iovec *in_sg,
|
struct iovec *in_sg,
|
||||||
int *num,
|
int *num,
|
||||||
|
@ -125,10 +127,19 @@ static ssize_t xen_9pfs_pdu_vmarshal(V9fsPDU *pdu,
|
||||||
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
|
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
|
||||||
struct iovec in_sg[2];
|
struct iovec in_sg[2];
|
||||||
int num;
|
int num;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
xen_9pfs_in_sg(&xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings],
|
xen_9pfs_in_sg(&xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings],
|
||||||
in_sg, &num, pdu->idx, ROUND_UP(offset + 128, 512));
|
in_sg, &num, pdu->idx, ROUND_UP(offset + 128, 512));
|
||||||
return v9fs_iov_vmarshal(in_sg, num, offset, 0, fmt, ap);
|
|
||||||
|
ret = v9fs_iov_vmarshal(in_sg, num, offset, 0, fmt, ap);
|
||||||
|
if (ret < 0) {
|
||||||
|
xen_pv_printf(&xen_9pfs->xendev, 0,
|
||||||
|
"Failed to encode VirtFS request type %d\n", pdu->id + 1);
|
||||||
|
xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
|
||||||
|
xen_9pfs_disconnect(&xen_9pfs->xendev);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t xen_9pfs_pdu_vunmarshal(V9fsPDU *pdu,
|
static ssize_t xen_9pfs_pdu_vunmarshal(V9fsPDU *pdu,
|
||||||
|
@ -139,15 +150,25 @@ static ssize_t xen_9pfs_pdu_vunmarshal(V9fsPDU *pdu,
|
||||||
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
|
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
|
||||||
struct iovec out_sg[2];
|
struct iovec out_sg[2];
|
||||||
int num;
|
int num;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
xen_9pfs_out_sg(&xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings],
|
xen_9pfs_out_sg(&xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings],
|
||||||
out_sg, &num, pdu->idx);
|
out_sg, &num, pdu->idx);
|
||||||
return v9fs_iov_vunmarshal(out_sg, num, offset, 0, fmt, ap);
|
|
||||||
|
ret = v9fs_iov_vunmarshal(out_sg, num, offset, 0, fmt, ap);
|
||||||
|
if (ret < 0) {
|
||||||
|
xen_pv_printf(&xen_9pfs->xendev, 0,
|
||||||
|
"Failed to decode VirtFS request type %d\n", pdu->id);
|
||||||
|
xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
|
||||||
|
xen_9pfs_disconnect(&xen_9pfs->xendev);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xen_9pfs_init_out_iov_from_pdu(V9fsPDU *pdu,
|
static void xen_9pfs_init_out_iov_from_pdu(V9fsPDU *pdu,
|
||||||
struct iovec **piov,
|
struct iovec **piov,
|
||||||
unsigned int *pniov)
|
unsigned int *pniov,
|
||||||
|
size_t size)
|
||||||
{
|
{
|
||||||
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
|
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
|
||||||
Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
|
Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
|
||||||
|
@ -169,11 +190,22 @@ static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu,
|
||||||
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
|
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
|
||||||
Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
|
Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
|
||||||
int num;
|
int num;
|
||||||
|
size_t buf_size;
|
||||||
|
|
||||||
g_free(ring->sg);
|
g_free(ring->sg);
|
||||||
|
|
||||||
ring->sg = g_malloc0(sizeof(*ring->sg) * 2);
|
ring->sg = g_malloc0(sizeof(*ring->sg) * 2);
|
||||||
xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size);
|
xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size);
|
||||||
|
|
||||||
|
buf_size = iov_size(ring->sg, num);
|
||||||
|
if (buf_size < size) {
|
||||||
|
xen_pv_printf(&xen_9pfs->xendev, 0, "Xen 9pfs request type %d"
|
||||||
|
"needs %zu bytes, buffer has %zu\n", pdu->id, size,
|
||||||
|
buf_size);
|
||||||
|
xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
|
||||||
|
xen_9pfs_disconnect(&xen_9pfs->xendev);
|
||||||
|
}
|
||||||
|
|
||||||
*piov = ring->sg;
|
*piov = ring->sg;
|
||||||
*pniov = num;
|
*pniov = num;
|
||||||
}
|
}
|
||||||
|
@ -217,7 +249,7 @@ static int xen_9pfs_init(struct XenDevice *xendev)
|
||||||
static int xen_9pfs_receive(Xen9pfsRing *ring)
|
static int xen_9pfs_receive(Xen9pfsRing *ring)
|
||||||
{
|
{
|
||||||
P9MsgHeader h;
|
P9MsgHeader h;
|
||||||
RING_IDX cons, prod, masked_prod, masked_cons;
|
RING_IDX cons, prod, masked_prod, masked_cons, queued;
|
||||||
V9fsPDU *pdu;
|
V9fsPDU *pdu;
|
||||||
|
|
||||||
if (ring->inprogress) {
|
if (ring->inprogress) {
|
||||||
|
@ -228,8 +260,8 @@ static int xen_9pfs_receive(Xen9pfsRing *ring)
|
||||||
prod = ring->intf->out_prod;
|
prod = ring->intf->out_prod;
|
||||||
xen_rmb();
|
xen_rmb();
|
||||||
|
|
||||||
if (xen_9pfs_queued(prod, cons, XEN_FLEX_RING_SIZE(ring->ring_order)) <
|
queued = xen_9pfs_queued(prod, cons, XEN_FLEX_RING_SIZE(ring->ring_order));
|
||||||
sizeof(h)) {
|
if (queued < sizeof(h)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ring->inprogress = true;
|
ring->inprogress = true;
|
||||||
|
@ -240,6 +272,9 @@ static int xen_9pfs_receive(Xen9pfsRing *ring)
|
||||||
xen_9pfs_read_packet((uint8_t *) &h, ring->ring.out, sizeof(h),
|
xen_9pfs_read_packet((uint8_t *) &h, ring->ring.out, sizeof(h),
|
||||||
masked_prod, &masked_cons,
|
masked_prod, &masked_cons,
|
||||||
XEN_FLEX_RING_SIZE(ring->ring_order));
|
XEN_FLEX_RING_SIZE(ring->ring_order));
|
||||||
|
if (queued < le32_to_cpu(h.size_le)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* cannot fail, because we only handle one request per ring at a time */
|
/* cannot fail, because we only handle one request per ring at a time */
|
||||||
pdu = pdu_alloc(&ring->priv->state);
|
pdu = pdu_alloc(&ring->priv->state);
|
||||||
|
@ -268,15 +303,30 @@ static void xen_9pfs_evtchn_event(void *opaque)
|
||||||
qemu_bh_schedule(ring->bh);
|
qemu_bh_schedule(ring->bh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void xen_9pfs_disconnect(struct XenDevice *xendev)
|
||||||
|
{
|
||||||
|
Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < xen_9pdev->num_rings; i++) {
|
||||||
|
if (xen_9pdev->rings[i].evtchndev != NULL) {
|
||||||
|
qemu_set_fd_handler(xenevtchn_fd(xen_9pdev->rings[i].evtchndev),
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
xenevtchn_unbind(xen_9pdev->rings[i].evtchndev,
|
||||||
|
xen_9pdev->rings[i].local_port);
|
||||||
|
xen_9pdev->rings[i].evtchndev = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int xen_9pfs_free(struct XenDevice *xendev)
|
static int xen_9pfs_free(struct XenDevice *xendev)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
|
Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
|
||||||
|
int i;
|
||||||
|
|
||||||
g_free(xen_9pdev->id);
|
if (xen_9pdev->rings[0].evtchndev != NULL) {
|
||||||
g_free(xen_9pdev->tag);
|
xen_9pfs_disconnect(xendev);
|
||||||
g_free(xen_9pdev->path);
|
}
|
||||||
g_free(xen_9pdev->security_model);
|
|
||||||
|
|
||||||
for (i = 0; i < xen_9pdev->num_rings; i++) {
|
for (i = 0; i < xen_9pdev->num_rings; i++) {
|
||||||
if (xen_9pdev->rings[i].data != NULL) {
|
if (xen_9pdev->rings[i].data != NULL) {
|
||||||
|
@ -289,16 +339,15 @@ static int xen_9pfs_free(struct XenDevice *xendev)
|
||||||
xen_9pdev->rings[i].intf,
|
xen_9pdev->rings[i].intf,
|
||||||
1);
|
1);
|
||||||
}
|
}
|
||||||
if (xen_9pdev->rings[i].evtchndev > 0) {
|
|
||||||
qemu_set_fd_handler(xenevtchn_fd(xen_9pdev->rings[i].evtchndev),
|
|
||||||
NULL, NULL, NULL);
|
|
||||||
xenevtchn_unbind(xen_9pdev->rings[i].evtchndev,
|
|
||||||
xen_9pdev->rings[i].local_port);
|
|
||||||
}
|
|
||||||
if (xen_9pdev->rings[i].bh != NULL) {
|
if (xen_9pdev->rings[i].bh != NULL) {
|
||||||
qemu_bh_delete(xen_9pdev->rings[i].bh);
|
qemu_bh_delete(xen_9pdev->rings[i].bh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free(xen_9pdev->id);
|
||||||
|
g_free(xen_9pdev->tag);
|
||||||
|
g_free(xen_9pdev->path);
|
||||||
|
g_free(xen_9pdev->security_model);
|
||||||
g_free(xen_9pdev->rings);
|
g_free(xen_9pdev->rings);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -422,11 +471,6 @@ static void xen_9pfs_alloc(struct XenDevice *xendev)
|
||||||
xenstore_write_be_int(xendev, "max-ring-page-order", MAX_RING_ORDER);
|
xenstore_write_be_int(xendev, "max-ring-page-order", MAX_RING_ORDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xen_9pfs_disconnect(struct XenDevice *xendev)
|
|
||||||
{
|
|
||||||
/* Dynamic hotplug of PV filesystems at runtime is not supported. */
|
|
||||||
}
|
|
||||||
|
|
||||||
struct XenDevOps xen_9pfs_ops = {
|
struct XenDevOps xen_9pfs_ops = {
|
||||||
.size = sizeof(Xen9pfsDev),
|
.size = sizeof(Xen9pfsDev),
|
||||||
.flags = DEVOPS_FLAG_NEED_GNTDEV,
|
.flags = DEVOPS_FLAG_NEED_GNTDEV,
|
||||||
|
|
|
@ -1010,7 +1010,7 @@ ETEXI
|
||||||
|
|
||||||
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
|
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
|
||||||
"-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n"
|
"-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n"
|
||||||
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n"
|
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd][,fmode=fmode][,dmode=dmode]\n"
|
||||||
" [[,throttling.bps-total=b]|[[,throttling.bps-read=r][,throttling.bps-write=w]]]\n"
|
" [[,throttling.bps-total=b]|[[,throttling.bps-read=r][,throttling.bps-write=w]]]\n"
|
||||||
" [[,throttling.iops-total=i]|[[,throttling.iops-read=r][,throttling.iops-write=w]]]\n"
|
" [[,throttling.iops-total=i]|[[,throttling.iops-read=r][,throttling.iops-write=w]]]\n"
|
||||||
" [[,throttling.bps-total-max=bm]|[[,throttling.bps-read-max=rm][,throttling.bps-write-max=wm]]]\n"
|
" [[,throttling.bps-total-max=bm]|[[,throttling.bps-read-max=rm][,throttling.bps-write-max=wm]]]\n"
|
||||||
|
@ -1020,7 +1020,7 @@ DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
|
|
||||||
@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,socket=@var{socket}|sock_fd=@var{sock_fd}]
|
@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,socket=@var{socket}|sock_fd=@var{sock_fd}][,fmode=@var{fmode}][,dmode=@var{dmode}]
|
||||||
@findex -fsdev
|
@findex -fsdev
|
||||||
Define a new file system device. Valid options are:
|
Define a new file system device. Valid options are:
|
||||||
@table @option
|
@table @option
|
||||||
|
@ -1061,6 +1061,12 @@ with virtfs-proxy-helper
|
||||||
Enables proxy filesystem driver to use passed socket descriptor for
|
Enables proxy filesystem driver to use passed socket descriptor for
|
||||||
communicating with virtfs-proxy-helper. Usually a helper like libvirt
|
communicating with virtfs-proxy-helper. Usually a helper like libvirt
|
||||||
will create socketpair and pass one of the fds as sock_fd
|
will create socketpair and pass one of the fds as sock_fd
|
||||||
|
@item fmode=@var{fmode}
|
||||||
|
Specifies the default mode for newly created files on the host. Works only
|
||||||
|
with security models "mapped-xattr" and "mapped-file".
|
||||||
|
@item dmode=@var{dmode}
|
||||||
|
Specifies the default mode for newly created directories on the host. Works
|
||||||
|
only with security models "mapped-xattr" and "mapped-file".
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
-fsdev option is used along with -device driver "virtio-9p-pci".
|
-fsdev option is used along with -device driver "virtio-9p-pci".
|
||||||
|
@ -1077,12 +1083,12 @@ ETEXI
|
||||||
|
|
||||||
DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
|
DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
|
||||||
"-virtfs local,path=path,mount_tag=tag,security_model=[mapped-xattr|mapped-file|passthrough|none]\n"
|
"-virtfs local,path=path,mount_tag=tag,security_model=[mapped-xattr|mapped-file|passthrough|none]\n"
|
||||||
" [,id=id][,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n",
|
" [,id=id][,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd][,fmode=fmode][,dmode=dmode]\n",
|
||||||
QEMU_ARCH_ALL)
|
QEMU_ARCH_ALL)
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
|
|
||||||
@item -virtfs @var{fsdriver}[,path=@var{path}],mount_tag=@var{mount_tag}[,security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,socket=@var{socket}|sock_fd=@var{sock_fd}]
|
@item -virtfs @var{fsdriver}[,path=@var{path}],mount_tag=@var{mount_tag}[,security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,socket=@var{socket}|sock_fd=@var{sock_fd}][,fmode=@var{fmode}][,dmode=@var{dmode}]
|
||||||
@findex -virtfs
|
@findex -virtfs
|
||||||
|
|
||||||
The general form of a Virtual File system pass-through options are:
|
The general form of a Virtual File system pass-through options are:
|
||||||
|
@ -1124,6 +1130,12 @@ will create socketpair and pass one of the fds as sock_fd
|
||||||
@item sock_fd
|
@item sock_fd
|
||||||
Enables proxy filesystem driver to use passed 'sock_fd' as the socket
|
Enables proxy filesystem driver to use passed 'sock_fd' as the socket
|
||||||
descriptor for interfacing with virtfs-proxy-helper
|
descriptor for interfacing with virtfs-proxy-helper
|
||||||
|
@item fmode=@var{fmode}
|
||||||
|
Specifies the default mode for newly created files on the host. Works only
|
||||||
|
with security models "mapped-xattr" and "mapped-file".
|
||||||
|
@item dmode=@var{dmode}
|
||||||
|
Specifies the default mode for newly created directories on the host. Works
|
||||||
|
only with security models "mapped-xattr" and "mapped-file".
|
||||||
@end table
|
@end table
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue