Merge remote-tracking branch 'aneesh/for-upstream' into staging
* aneesh/for-upstream: hw/9pfs: Add support to use named socket for proxy FS hw/9pfs: man page for proxy helper hw/9pfs: Documentation changes related to proxy fs hw/9pfs: Proxy getversion hw/9pfs: xattr interfaces in proxy filesystem driver hw/9pfs: File ownership and others hw/9pfs: Add stat/readlink/statfs for proxy FS hw/9pfs: Create other filesystem objects hw/9pfs: Open and create files hw/9pfs: File system helper process for qemu 9p proxy FS hw/9pfs: Add new proxy filesystem driver hw/9pfs: Add validation to {un}marshal code hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file hw/9pfs: Move opt validation to FsDriver callback
This commit is contained in:
commit
74b728e4f3
15
Makefile
15
Makefile
@ -38,6 +38,7 @@ LIBS+=-lz $(LIBS_TOOLS)
|
|||||||
|
|
||||||
ifdef BUILD_DOCS
|
ifdef BUILD_DOCS
|
||||||
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 QMP/qmp-commands.txt
|
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 QMP/qmp-commands.txt
|
||||||
|
DOCS+=fsdev/virtfs-proxy-helper.1
|
||||||
else
|
else
|
||||||
DOCS=
|
DOCS=
|
||||||
endif
|
endif
|
||||||
@ -155,6 +156,9 @@ qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
|
|||||||
qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
|
qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
|
||||||
qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
|
qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
|
||||||
|
|
||||||
|
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
|
||||||
|
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
|
||||||
|
|
||||||
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
|
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
|
||||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@")
|
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@")
|
||||||
|
|
||||||
@ -286,7 +290,10 @@ ifdef CONFIG_POSIX
|
|||||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
|
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
|
||||||
$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
|
$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
|
||||||
endif
|
endif
|
||||||
|
ifdef CONFIG_VIRTFS
|
||||||
|
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||||
|
$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
|
||||||
|
endif
|
||||||
install-sysconfig:
|
install-sysconfig:
|
||||||
$(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)/qemu"
|
$(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)/qemu"
|
||||||
$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(sysconfdir)/qemu"
|
$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(sysconfdir)/qemu"
|
||||||
@ -370,6 +377,12 @@ qemu-img.1: qemu-img.texi qemu-img-cmds.texi
|
|||||||
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@, \
|
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@, \
|
||||||
" GEN $@")
|
" GEN $@")
|
||||||
|
|
||||||
|
fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
|
||||||
|
$(call quiet-command, \
|
||||||
|
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< fsdev/virtfs-proxy-helper.pod && \
|
||||||
|
pod2man --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \
|
||||||
|
" GEN $@")
|
||||||
|
|
||||||
qemu-nbd.8: qemu-nbd.texi
|
qemu-nbd.8: qemu-nbd.texi
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
|
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
|
||||||
|
@ -61,7 +61,7 @@ ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
|
|||||||
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
|
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
|
||||||
# only pull in the actual virtio-9p device if we also enabled virtio.
|
# only pull in the actual virtio-9p device if we also enabled virtio.
|
||||||
CONFIG_REALLY_VIRTFS=y
|
CONFIG_REALLY_VIRTFS=y
|
||||||
fsdev-nested-y = qemu-fsdev.o
|
fsdev-nested-y = qemu-fsdev.o virtio-9p-marshal.o
|
||||||
else
|
else
|
||||||
fsdev-nested-y = qemu-fsdev-dummy.o
|
fsdev-nested-y = qemu-fsdev-dummy.o
|
||||||
endif
|
endif
|
||||||
@ -311,6 +311,7 @@ hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
|
|||||||
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o
|
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o
|
||||||
9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o virtio-9p-synth.o
|
9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o virtio-9p-synth.o
|
||||||
9pfs-nested-$(CONFIG_OPEN_BY_HANDLE) += virtio-9p-handle.o
|
9pfs-nested-$(CONFIG_OPEN_BY_HANDLE) += virtio-9p-handle.o
|
||||||
|
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-proxy.o
|
||||||
|
|
||||||
hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
|
hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
|
||||||
$(addprefix 9pfs/, $(9pfs-nested-y)): QEMU_CFLAGS+=$(GLIB_CFLAGS)
|
$(addprefix 9pfs/, $(9pfs-nested-y)): QEMU_CFLAGS+=$(GLIB_CFLAGS)
|
||||||
|
19
configure
vendored
19
configure
vendored
@ -1966,6 +1966,22 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# libcap probe
|
||||||
|
|
||||||
|
if test "$cap" != "no" ; then
|
||||||
|
cat > $TMPC <<EOF
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/capability.h>
|
||||||
|
int main(void) { cap_t caps; caps = cap_init(); }
|
||||||
|
EOF
|
||||||
|
if compile_prog "" "-lcap" ; then
|
||||||
|
cap=yes
|
||||||
|
else
|
||||||
|
cap=no
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# pthread probe
|
# pthread probe
|
||||||
PTHREADLIBS_LIST="-pthread -lpthread -lpthreadGC2"
|
PTHREADLIBS_LIST="-pthread -lpthread -lpthreadGC2"
|
||||||
@ -2767,6 +2783,9 @@ confdir=$sysconfdir$confsuffix
|
|||||||
tools=
|
tools=
|
||||||
if test "$softmmu" = yes ; then
|
if test "$softmmu" = yes ; then
|
||||||
tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
|
tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
|
||||||
|
if [ "$cap" = "yes" -a "$linux" = "yes" ] ; then
|
||||||
|
tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
|
||||||
|
fi
|
||||||
if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
|
if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
|
||||||
tools="qemu-nbd\$(EXESUF) $tools"
|
tools="qemu-nbd\$(EXESUF) $tools"
|
||||||
if [ "$guest_agent" = "yes" ]; then
|
if [ "$guest_agent" = "yes" ]; then
|
||||||
|
@ -57,10 +57,22 @@ typedef struct extended_ops {
|
|||||||
*/
|
*/
|
||||||
#define V9FS_SM_NONE 0x00000010
|
#define V9FS_SM_NONE 0x00000010
|
||||||
#define V9FS_RDONLY 0x00000020
|
#define V9FS_RDONLY 0x00000020
|
||||||
|
#define V9FS_PROXY_SOCK_FD 0x00000040
|
||||||
|
#define V9FS_PROXY_SOCK_NAME 0x00000080
|
||||||
|
|
||||||
#define V9FS_SEC_MASK 0x0000001C
|
#define V9FS_SEC_MASK 0x0000001C
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct FileOperations FileOperations;
|
||||||
|
/*
|
||||||
|
* Structure to store the various fsdev's passed through command line.
|
||||||
|
*/
|
||||||
|
typedef struct FsDriverEntry {
|
||||||
|
char *fsdev_id;
|
||||||
|
char *path;
|
||||||
|
int export_flags;
|
||||||
|
FileOperations *ops;
|
||||||
|
} FsDriverEntry;
|
||||||
|
|
||||||
typedef struct FsContext
|
typedef struct FsContext
|
||||||
{
|
{
|
||||||
@ -82,8 +94,9 @@ typedef union V9fsFidOpenState V9fsFidOpenState;
|
|||||||
|
|
||||||
void cred_init(FsCred *);
|
void cred_init(FsCred *);
|
||||||
|
|
||||||
typedef struct FileOperations
|
struct FileOperations
|
||||||
{
|
{
|
||||||
|
int (*parse_opts)(QemuOpts *, struct FsDriverEntry *);
|
||||||
int (*init)(struct FsContext *);
|
int (*init)(struct FsContext *);
|
||||||
int (*lstat)(FsContext *, V9fsPath *, struct stat *);
|
int (*lstat)(FsContext *, V9fsPath *, struct stat *);
|
||||||
ssize_t (*readlink)(FsContext *, V9fsPath *, char *, size_t);
|
ssize_t (*readlink)(FsContext *, V9fsPath *, char *, size_t);
|
||||||
@ -128,6 +141,6 @@ typedef struct FileOperations
|
|||||||
V9fsPath *newdir, const char *new_name);
|
V9fsPath *newdir, const char *new_name);
|
||||||
int (*unlinkat)(FsContext *ctx, V9fsPath *dir, const char *name, int flags);
|
int (*unlinkat)(FsContext *ctx, V9fsPath *dir, const char *name, int flags);
|
||||||
void *opaque;
|
void *opaque;
|
||||||
} FileOperations;
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,16 +27,15 @@ static FsDriverTable FsDrivers[] = {
|
|||||||
{ .name = "handle", .ops = &handle_ops},
|
{ .name = "handle", .ops = &handle_ops},
|
||||||
#endif
|
#endif
|
||||||
{ .name = "synth", .ops = &synth_ops},
|
{ .name = "synth", .ops = &synth_ops},
|
||||||
|
{ .name = "proxy", .ops = &proxy_ops},
|
||||||
};
|
};
|
||||||
|
|
||||||
int qemu_fsdev_add(QemuOpts *opts)
|
int qemu_fsdev_add(QemuOpts *opts)
|
||||||
{
|
{
|
||||||
struct FsDriverListEntry *fsle;
|
|
||||||
int i;
|
int i;
|
||||||
|
struct FsDriverListEntry *fsle;
|
||||||
const char *fsdev_id = qemu_opts_id(opts);
|
const char *fsdev_id = qemu_opts_id(opts);
|
||||||
const char *fsdriver = qemu_opt_get(opts, "fsdriver");
|
const char *fsdriver = qemu_opt_get(opts, "fsdriver");
|
||||||
const char *path = qemu_opt_get(opts, "path");
|
|
||||||
const char *sec_model = qemu_opt_get(opts, "security_model");
|
|
||||||
const char *writeout = qemu_opt_get(opts, "writeout");
|
const char *writeout = qemu_opt_get(opts, "writeout");
|
||||||
bool ro = qemu_opt_get_bool(opts, "readonly", 0);
|
bool ro = qemu_opt_get_bool(opts, "readonly", 0);
|
||||||
|
|
||||||
@ -61,29 +60,9 @@ int qemu_fsdev_add(QemuOpts *opts)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(fsdriver, "local") && !sec_model) {
|
fsle = g_malloc0(sizeof(*fsle));
|
||||||
fprintf(stderr, "security model not specified, "
|
|
||||||
"local fs needs security model\nvalid options are:"
|
|
||||||
"\tsecurity_model=[passthrough|mapped|none]\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(fsdriver, "local") && sec_model) {
|
|
||||||
fprintf(stderr, "only local fs driver needs security model\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!path) {
|
|
||||||
fprintf(stderr, "fsdev: No path specified.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fsle = g_malloc(sizeof(*fsle));
|
|
||||||
|
|
||||||
fsle->fse.fsdev_id = g_strdup(fsdev_id);
|
fsle->fse.fsdev_id = g_strdup(fsdev_id);
|
||||||
fsle->fse.path = g_strdup(path);
|
|
||||||
fsle->fse.ops = FsDrivers[i].ops;
|
fsle->fse.ops = FsDrivers[i].ops;
|
||||||
fsle->fse.export_flags = 0;
|
|
||||||
if (writeout) {
|
if (writeout) {
|
||||||
if (!strcmp(writeout, "immediate")) {
|
if (!strcmp(writeout, "immediate")) {
|
||||||
fsle->fse.export_flags |= V9FS_IMMEDIATE_WRITEOUT;
|
fsle->fse.export_flags |= V9FS_IMMEDIATE_WRITEOUT;
|
||||||
@ -95,22 +74,12 @@ int qemu_fsdev_add(QemuOpts *opts)
|
|||||||
fsle->fse.export_flags &= ~V9FS_RDONLY;
|
fsle->fse.export_flags &= ~V9FS_RDONLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(fsdriver, "local")) {
|
if (fsle->fse.ops->parse_opts) {
|
||||||
goto done;
|
if (fsle->fse.ops->parse_opts(opts, &fsle->fse)) {
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(sec_model, "passthrough")) {
|
|
||||||
fsle->fse.export_flags |= V9FS_SM_PASSTHROUGH;
|
|
||||||
} else if (!strcmp(sec_model, "mapped")) {
|
|
||||||
fsle->fse.export_flags |= V9FS_SM_MAPPED;
|
|
||||||
} else if (!strcmp(sec_model, "none")) {
|
|
||||||
fsle->fse.export_flags |= V9FS_SM_NONE;
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Invalid security model %s specified, valid options are"
|
|
||||||
"\n\t [passthrough|mapped|none]\n", sec_model);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
done:
|
}
|
||||||
|
|
||||||
QTAILQ_INSERT_TAIL(&fsdriver_entries, fsle, next);
|
QTAILQ_INSERT_TAIL(&fsdriver_entries, fsle, next);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -34,16 +34,6 @@ typedef struct FsDriverTable {
|
|||||||
FileOperations *ops;
|
FileOperations *ops;
|
||||||
} FsDriverTable;
|
} FsDriverTable;
|
||||||
|
|
||||||
/*
|
|
||||||
* Structure to store the various fsdev's passed through command line.
|
|
||||||
*/
|
|
||||||
typedef struct FsDriverEntry {
|
|
||||||
char *fsdev_id;
|
|
||||||
char *path;
|
|
||||||
int export_flags;
|
|
||||||
FileOperations *ops;
|
|
||||||
} FsDriverEntry;
|
|
||||||
|
|
||||||
typedef struct FsDriverListEntry {
|
typedef struct FsDriverListEntry {
|
||||||
FsDriverEntry fse;
|
FsDriverEntry fse;
|
||||||
QTAILQ_ENTRY(FsDriverListEntry) next;
|
QTAILQ_ENTRY(FsDriverListEntry) next;
|
||||||
@ -54,4 +44,5 @@ FsDriverEntry *get_fsdev_fsentry(char *id);
|
|||||||
extern FileOperations local_ops;
|
extern FileOperations local_ops;
|
||||||
extern FileOperations handle_ops;
|
extern FileOperations handle_ops;
|
||||||
extern FileOperations synth_ops;
|
extern FileOperations synth_ops;
|
||||||
|
extern FileOperations proxy_ops;
|
||||||
#endif
|
#endif
|
||||||
|
1120
fsdev/virtfs-proxy-helper.c
Normal file
1120
fsdev/virtfs-proxy-helper.c
Normal file
File diff suppressed because it is too large
Load Diff
63
fsdev/virtfs-proxy-helper.texi
Normal file
63
fsdev/virtfs-proxy-helper.texi
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
@example
|
||||||
|
@c man begin SYNOPSIS
|
||||||
|
usage: virtfs-proxy-helper options
|
||||||
|
@c man end
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@c man begin DESCRIPTION
|
||||||
|
@table @description
|
||||||
|
Pass-through security model in QEMU 9p server needs root privilege to do
|
||||||
|
few file operations (like chown, chmod to any mode/uid:gid). There are two
|
||||||
|
issues in pass-through security model
|
||||||
|
|
||||||
|
1) TOCTTOU vulnerability: Following symbolic links in the server could
|
||||||
|
provide access to files beyond 9p export path.
|
||||||
|
|
||||||
|
2) Running QEMU with root privilege could be a security issue.
|
||||||
|
|
||||||
|
To overcome above issues, following approach is used: A new filesytem
|
||||||
|
type 'proxy' is introduced. Proxy FS uses chroot + socket combination
|
||||||
|
for securing the vulnerability known with following symbolic links.
|
||||||
|
Intention of adding a new filesystem type is to allow qemu to run
|
||||||
|
in non-root mode, but doing privileged operations using socket IO.
|
||||||
|
|
||||||
|
Proxy helper(a stand alone binary part of qemu) is invoked with
|
||||||
|
root privileges. Proxy helper chroots into 9p export path and creates
|
||||||
|
a socket pair or a named socket based on the command line parameter.
|
||||||
|
Qemu and proxy helper communicate using this socket. QEMU proxy fs
|
||||||
|
driver sends filesystem request to proxy helper and receives the
|
||||||
|
response from it.
|
||||||
|
|
||||||
|
Proxy helper is designed so that it can drop the root privilege with
|
||||||
|
retaining capbilities needed for doing filesystem operations only.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
@c man end
|
||||||
|
|
||||||
|
@c man begin OPTIONS
|
||||||
|
The following options are supported:
|
||||||
|
@table @option
|
||||||
|
@item -h
|
||||||
|
@findex -h
|
||||||
|
Display help and exit
|
||||||
|
@item -p|--path path
|
||||||
|
Path to export for proxy filesystem driver
|
||||||
|
@item -f|--fd socket-id
|
||||||
|
Use given file descriptor as socket descriptor for communicating with
|
||||||
|
qemu proxy fs drier. Usually a helper like libvirt will create
|
||||||
|
socketpair and pass one of the fds as parameter to -f|--fd
|
||||||
|
@item -s|--socket socket-file
|
||||||
|
Creates named socket file for communicating with qemu proxy fs driver
|
||||||
|
@item -u|--uid uid -g|--gid gid
|
||||||
|
uid:gid combination to give access to named socket file
|
||||||
|
@item -n|--nodaemon
|
||||||
|
Run as a normal program. By default program will run in daemon mode
|
||||||
|
@end table
|
||||||
|
@c man end
|
||||||
|
|
||||||
|
@setfilename virtfs-proxy-helper
|
||||||
|
@settitle QEMU 9p virtfs proxy filesystem helper
|
||||||
|
|
||||||
|
@c man begin AUTHOR
|
||||||
|
M. Mohan Kumar
|
||||||
|
@c man end
|
323
fsdev/virtio-9p-marshal.c
Normal file
323
fsdev/virtio-9p-marshal.c
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
/*
|
||||||
|
* Virtio 9p backend
|
||||||
|
*
|
||||||
|
* Copyright IBM, Corp. 2010
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anthony Liguori <aliguori@us.ibm.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||||
|
* the COPYING file in the top-level directory.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gprintf.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "compiler.h"
|
||||||
|
#include "virtio-9p-marshal.h"
|
||||||
|
#include "bswap.h"
|
||||||
|
|
||||||
|
void v9fs_string_free(V9fsString *str)
|
||||||
|
{
|
||||||
|
g_free(str->data);
|
||||||
|
str->data = NULL;
|
||||||
|
str->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void v9fs_string_null(V9fsString *str)
|
||||||
|
{
|
||||||
|
v9fs_string_free(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCC_FMT_ATTR(2, 3)
|
||||||
|
v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
v9fs_string_free(str);
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
str->size = g_vasprintf(&str->data, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
|
||||||
|
{
|
||||||
|
v9fs_string_free(lhs);
|
||||||
|
v9fs_string_sprintf(lhs, "%s", rhs->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ssize_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count,
|
||||||
|
size_t offset, size_t size, int pack)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
size_t copied = 0;
|
||||||
|
size_t req_size = size;
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; size && i < sg_count; i++) {
|
||||||
|
size_t len;
|
||||||
|
if (offset >= sg[i].iov_len) {
|
||||||
|
/* skip this sg */
|
||||||
|
offset -= sg[i].iov_len;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
len = MIN(sg[i].iov_len - offset, size);
|
||||||
|
if (pack) {
|
||||||
|
memcpy(sg[i].iov_base + offset, addr, len);
|
||||||
|
} else {
|
||||||
|
memcpy(addr, sg[i].iov_base + offset, len);
|
||||||
|
}
|
||||||
|
size -= len;
|
||||||
|
copied += len;
|
||||||
|
addr += len;
|
||||||
|
if (size) {
|
||||||
|
offset = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (copied < req_size) {
|
||||||
|
/*
|
||||||
|
* We copied less that requested size. error out
|
||||||
|
*/
|
||||||
|
return -ENOBUFS;
|
||||||
|
}
|
||||||
|
return copied;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num,
|
||||||
|
size_t offset, size_t size)
|
||||||
|
{
|
||||||
|
return v9fs_packunpack(dst, out_sg, out_num, offset, size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset,
|
||||||
|
const void *src, size_t size)
|
||||||
|
{
|
||||||
|
return v9fs_packunpack((void *)src, in_sg, in_num, offset, size, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
|
||||||
|
int bswap, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
va_list ap;
|
||||||
|
ssize_t copied = 0;
|
||||||
|
size_t old_offset = offset;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
for (i = 0; fmt[i]; i++) {
|
||||||
|
switch (fmt[i]) {
|
||||||
|
case 'b': {
|
||||||
|
uint8_t *valp = va_arg(ap, uint8_t *);
|
||||||
|
copied = v9fs_unpack(valp, out_sg, out_num, offset, sizeof(*valp));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'w': {
|
||||||
|
uint16_t val, *valp;
|
||||||
|
valp = va_arg(ap, uint16_t *);
|
||||||
|
copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
|
||||||
|
if (bswap) {
|
||||||
|
*valp = le16_to_cpu(val);
|
||||||
|
} else {
|
||||||
|
*valp = val;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'd': {
|
||||||
|
uint32_t val, *valp;
|
||||||
|
valp = va_arg(ap, uint32_t *);
|
||||||
|
copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
|
||||||
|
if (bswap) {
|
||||||
|
*valp = le32_to_cpu(val);
|
||||||
|
} else {
|
||||||
|
*valp = val;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'q': {
|
||||||
|
uint64_t val, *valp;
|
||||||
|
valp = va_arg(ap, uint64_t *);
|
||||||
|
copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
|
||||||
|
if (bswap) {
|
||||||
|
*valp = le64_to_cpu(val);
|
||||||
|
} else {
|
||||||
|
*valp = val;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's': {
|
||||||
|
V9fsString *str = va_arg(ap, V9fsString *);
|
||||||
|
copied = v9fs_unmarshal(out_sg, out_num, offset, bswap,
|
||||||
|
"w", &str->size);
|
||||||
|
if (copied > 0) {
|
||||||
|
offset += copied;
|
||||||
|
str->data = g_malloc(str->size + 1);
|
||||||
|
copied = v9fs_unpack(str->data, out_sg, out_num, offset,
|
||||||
|
str->size);
|
||||||
|
if (copied > 0) {
|
||||||
|
str->data[str->size] = 0;
|
||||||
|
} else {
|
||||||
|
v9fs_string_free(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'Q': {
|
||||||
|
V9fsQID *qidp = va_arg(ap, V9fsQID *);
|
||||||
|
copied = v9fs_unmarshal(out_sg, out_num, offset, bswap, "bdq",
|
||||||
|
&qidp->type, &qidp->version, &qidp->path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'S': {
|
||||||
|
V9fsStat *statp = va_arg(ap, V9fsStat *);
|
||||||
|
copied = v9fs_unmarshal(out_sg, out_num, offset, bswap,
|
||||||
|
"wwdQdddqsssssddd",
|
||||||
|
&statp->size, &statp->type, &statp->dev,
|
||||||
|
&statp->qid, &statp->mode, &statp->atime,
|
||||||
|
&statp->mtime, &statp->length,
|
||||||
|
&statp->name, &statp->uid, &statp->gid,
|
||||||
|
&statp->muid, &statp->extension,
|
||||||
|
&statp->n_uid, &statp->n_gid,
|
||||||
|
&statp->n_muid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'I': {
|
||||||
|
V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
|
||||||
|
copied = v9fs_unmarshal(out_sg, out_num, offset, bswap,
|
||||||
|
"ddddqqqqq",
|
||||||
|
&iattr->valid, &iattr->mode,
|
||||||
|
&iattr->uid, &iattr->gid, &iattr->size,
|
||||||
|
&iattr->atime_sec, &iattr->atime_nsec,
|
||||||
|
&iattr->mtime_sec, &iattr->mtime_nsec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (copied < 0) {
|
||||||
|
va_end(ap);
|
||||||
|
return copied;
|
||||||
|
}
|
||||||
|
offset += copied;
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return offset - old_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
|
||||||
|
int bswap, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
va_list ap;
|
||||||
|
ssize_t copied = 0;
|
||||||
|
size_t old_offset = offset;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
for (i = 0; fmt[i]; i++) {
|
||||||
|
switch (fmt[i]) {
|
||||||
|
case 'b': {
|
||||||
|
uint8_t val = va_arg(ap, int);
|
||||||
|
copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'w': {
|
||||||
|
uint16_t val;
|
||||||
|
if (bswap) {
|
||||||
|
cpu_to_le16w(&val, va_arg(ap, int));
|
||||||
|
} else {
|
||||||
|
val = va_arg(ap, int);
|
||||||
|
}
|
||||||
|
copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'd': {
|
||||||
|
uint32_t val;
|
||||||
|
if (bswap) {
|
||||||
|
cpu_to_le32w(&val, va_arg(ap, uint32_t));
|
||||||
|
} else {
|
||||||
|
val = va_arg(ap, uint32_t);
|
||||||
|
}
|
||||||
|
copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'q': {
|
||||||
|
uint64_t val;
|
||||||
|
if (bswap) {
|
||||||
|
cpu_to_le64w(&val, va_arg(ap, uint64_t));
|
||||||
|
} else {
|
||||||
|
val = va_arg(ap, uint64_t);
|
||||||
|
}
|
||||||
|
copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's': {
|
||||||
|
V9fsString *str = va_arg(ap, V9fsString *);
|
||||||
|
copied = v9fs_marshal(in_sg, in_num, offset, bswap,
|
||||||
|
"w", str->size);
|
||||||
|
if (copied > 0) {
|
||||||
|
offset += copied;
|
||||||
|
copied = v9fs_pack(in_sg, in_num, offset, str->data, str->size);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'Q': {
|
||||||
|
V9fsQID *qidp = va_arg(ap, V9fsQID *);
|
||||||
|
copied = v9fs_marshal(in_sg, in_num, offset, bswap, "bdq",
|
||||||
|
qidp->type, qidp->version, qidp->path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'S': {
|
||||||
|
V9fsStat *statp = va_arg(ap, V9fsStat *);
|
||||||
|
copied = v9fs_marshal(in_sg, in_num, offset, bswap,
|
||||||
|
"wwdQdddqsssssddd",
|
||||||
|
statp->size, statp->type, statp->dev,
|
||||||
|
&statp->qid, statp->mode, statp->atime,
|
||||||
|
statp->mtime, statp->length, &statp->name,
|
||||||
|
&statp->uid, &statp->gid, &statp->muid,
|
||||||
|
&statp->extension, statp->n_uid,
|
||||||
|
statp->n_gid, statp->n_muid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'A': {
|
||||||
|
V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
|
||||||
|
copied = v9fs_marshal(in_sg, in_num, offset, bswap,
|
||||||
|
"qQdddqqqqqqqqqqqqqqq",
|
||||||
|
statp->st_result_mask,
|
||||||
|
&statp->qid, statp->st_mode,
|
||||||
|
statp->st_uid, statp->st_gid,
|
||||||
|
statp->st_nlink, statp->st_rdev,
|
||||||
|
statp->st_size, statp->st_blksize,
|
||||||
|
statp->st_blocks, statp->st_atime_sec,
|
||||||
|
statp->st_atime_nsec, statp->st_mtime_sec,
|
||||||
|
statp->st_mtime_nsec, statp->st_ctime_sec,
|
||||||
|
statp->st_ctime_nsec, statp->st_btime_sec,
|
||||||
|
statp->st_btime_nsec, statp->st_gen,
|
||||||
|
statp->st_data_version);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (copied < 0) {
|
||||||
|
va_end(ap);
|
||||||
|
return copied;
|
||||||
|
}
|
||||||
|
offset += copied;
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return offset - old_offset;
|
||||||
|
}
|
90
fsdev/virtio-9p-marshal.h
Normal file
90
fsdev/virtio-9p-marshal.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#ifndef _QEMU_VIRTIO_9P_MARSHAL_H
|
||||||
|
#define _QEMU_VIRTIO_9P_MARSHAL_H
|
||||||
|
|
||||||
|
typedef struct V9fsString
|
||||||
|
{
|
||||||
|
uint16_t size;
|
||||||
|
char *data;
|
||||||
|
} V9fsString;
|
||||||
|
|
||||||
|
typedef struct V9fsQID
|
||||||
|
{
|
||||||
|
int8_t type;
|
||||||
|
int32_t version;
|
||||||
|
int64_t path;
|
||||||
|
} V9fsQID;
|
||||||
|
|
||||||
|
typedef struct V9fsStat
|
||||||
|
{
|
||||||
|
int16_t size;
|
||||||
|
int16_t type;
|
||||||
|
int32_t dev;
|
||||||
|
V9fsQID qid;
|
||||||
|
int32_t mode;
|
||||||
|
int32_t atime;
|
||||||
|
int32_t mtime;
|
||||||
|
int64_t length;
|
||||||
|
V9fsString name;
|
||||||
|
V9fsString uid;
|
||||||
|
V9fsString gid;
|
||||||
|
V9fsString muid;
|
||||||
|
/* 9p2000.u */
|
||||||
|
V9fsString extension;
|
||||||
|
int32_t n_uid;
|
||||||
|
int32_t n_gid;
|
||||||
|
int32_t n_muid;
|
||||||
|
} V9fsStat;
|
||||||
|
|
||||||
|
typedef struct V9fsIattr
|
||||||
|
{
|
||||||
|
int32_t valid;
|
||||||
|
int32_t mode;
|
||||||
|
int32_t uid;
|
||||||
|
int32_t gid;
|
||||||
|
int64_t size;
|
||||||
|
int64_t atime_sec;
|
||||||
|
int64_t atime_nsec;
|
||||||
|
int64_t mtime_sec;
|
||||||
|
int64_t mtime_nsec;
|
||||||
|
} V9fsIattr;
|
||||||
|
|
||||||
|
typedef struct V9fsStatDotl {
|
||||||
|
uint64_t st_result_mask;
|
||||||
|
V9fsQID qid;
|
||||||
|
uint32_t st_mode;
|
||||||
|
uint32_t st_uid;
|
||||||
|
uint32_t st_gid;
|
||||||
|
uint64_t st_nlink;
|
||||||
|
uint64_t st_rdev;
|
||||||
|
uint64_t st_size;
|
||||||
|
uint64_t st_blksize;
|
||||||
|
uint64_t st_blocks;
|
||||||
|
uint64_t st_atime_sec;
|
||||||
|
uint64_t st_atime_nsec;
|
||||||
|
uint64_t st_mtime_sec;
|
||||||
|
uint64_t st_mtime_nsec;
|
||||||
|
uint64_t st_ctime_sec;
|
||||||
|
uint64_t st_ctime_nsec;
|
||||||
|
uint64_t st_btime_sec;
|
||||||
|
uint64_t st_btime_nsec;
|
||||||
|
uint64_t st_gen;
|
||||||
|
uint64_t st_data_version;
|
||||||
|
} V9fsStatDotl;
|
||||||
|
|
||||||
|
static inline void v9fs_string_init(V9fsString *str)
|
||||||
|
{
|
||||||
|
str->data = NULL;
|
||||||
|
str->size = 0;
|
||||||
|
}
|
||||||
|
extern void v9fs_string_free(V9fsString *str);
|
||||||
|
extern void v9fs_string_null(V9fsString *str);
|
||||||
|
extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...);
|
||||||
|
extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs);
|
||||||
|
|
||||||
|
ssize_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset,
|
||||||
|
const void *src, size_t size);
|
||||||
|
ssize_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
|
||||||
|
int bswap, const char *fmt, ...);
|
||||||
|
ssize_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
|
||||||
|
int bswap, const char *fmt, ...);
|
||||||
|
#endif
|
@ -77,16 +77,19 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fse->path || !conf->tag) {
|
if (!conf->tag) {
|
||||||
/* we haven't specified a mount_tag or the path */
|
/* we haven't specified a mount_tag */
|
||||||
fprintf(stderr, "fsdev with id %s needs path "
|
fprintf(stderr, "fsdev with id %s needs mount_tag arguments\n",
|
||||||
"and Virtio-9p device needs mount_tag arguments\n",
|
|
||||||
conf->fsdev_id);
|
conf->fsdev_id);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->ctx.export_flags = fse->export_flags;
|
s->ctx.export_flags = fse->export_flags;
|
||||||
|
if (fse->path) {
|
||||||
s->ctx.fs_root = g_strdup(fse->path);
|
s->ctx.fs_root = g_strdup(fse->path);
|
||||||
|
} else {
|
||||||
|
s->ctx.fs_root = NULL;
|
||||||
|
}
|
||||||
s->ctx.exops.get_st_gen = NULL;
|
s->ctx.exops.get_st_gen = NULL;
|
||||||
|
|
||||||
if (fse->export_flags & V9FS_SM_PASSTHROUGH) {
|
if (fse->export_flags & V9FS_SM_PASSTHROUGH) {
|
||||||
|
@ -641,7 +641,27 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int handle_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
|
||||||
|
{
|
||||||
|
const char *sec_model = qemu_opt_get(opts, "security_model");
|
||||||
|
const char *path = qemu_opt_get(opts, "path");
|
||||||
|
|
||||||
|
if (sec_model) {
|
||||||
|
fprintf(stderr, "Invalid argument security_model specified with handle fsdriver\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
fprintf(stderr, "fsdev: No path specified.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fse->path = g_strdup(path);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
FileOperations handle_ops = {
|
FileOperations handle_ops = {
|
||||||
|
.parse_opts = handle_parse_opts,
|
||||||
.init = handle_init,
|
.init = handle_init,
|
||||||
.lstat = handle_lstat,
|
.lstat = handle_lstat,
|
||||||
.readlink = handle_readlink,
|
.readlink = handle_readlink,
|
||||||
|
@ -756,7 +756,41 @@ static int local_init(FsContext *ctx)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
|
||||||
|
{
|
||||||
|
const char *sec_model = qemu_opt_get(opts, "security_model");
|
||||||
|
const char *path = qemu_opt_get(opts, "path");
|
||||||
|
|
||||||
|
if (!sec_model) {
|
||||||
|
fprintf(stderr, "security model not specified, "
|
||||||
|
"local fs needs security model\nvalid options are:"
|
||||||
|
"\tsecurity_model=[passthrough|mapped|none]\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(sec_model, "passthrough")) {
|
||||||
|
fse->export_flags |= V9FS_SM_PASSTHROUGH;
|
||||||
|
} else if (!strcmp(sec_model, "mapped")) {
|
||||||
|
fse->export_flags |= V9FS_SM_MAPPED;
|
||||||
|
} else if (!strcmp(sec_model, "none")) {
|
||||||
|
fse->export_flags |= V9FS_SM_NONE;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Invalid security model %s specified, valid options are"
|
||||||
|
"\n\t [passthrough|mapped|none]\n", sec_model);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
fprintf(stderr, "fsdev: No path specified.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fse->path = g_strdup(path);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
FileOperations local_ops = {
|
FileOperations local_ops = {
|
||||||
|
.parse_opts = local_parse_opts,
|
||||||
.init = local_init,
|
.init = local_init,
|
||||||
.lstat = local_lstat,
|
.lstat = local_lstat,
|
||||||
.readlink = local_readlink,
|
.readlink = local_readlink,
|
||||||
|
1210
hw/9pfs/virtio-9p-proxy.c
Normal file
1210
hw/9pfs/virtio-9p-proxy.c
Normal file
File diff suppressed because it is too large
Load Diff
95
hw/9pfs/virtio-9p-proxy.h
Normal file
95
hw/9pfs/virtio-9p-proxy.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Virtio 9p Proxy callback
|
||||||
|
*
|
||||||
|
* Copyright IBM, Corp. 2011
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* M. Mohan Kumar <mohan@in.ibm.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||||
|
* the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
#ifndef _QEMU_VIRTIO_9P_PROXY_H
|
||||||
|
#define _QEMU_VIRTIO_9P_PROXY_H
|
||||||
|
|
||||||
|
#define PROXY_MAX_IO_SZ (64 * 1024)
|
||||||
|
#define V9FS_FD_VALID INT_MAX
|
||||||
|
|
||||||
|
/*
|
||||||
|
* proxy iovec only support one element and
|
||||||
|
* marsha/unmarshal doesn't do little endian conversion.
|
||||||
|
*/
|
||||||
|
#define proxy_unmarshal(in_sg, offset, fmt, args...) \
|
||||||
|
v9fs_unmarshal(in_sg, 1, offset, 0, fmt, ##args)
|
||||||
|
#define proxy_marshal(out_sg, offset, fmt, args...) \
|
||||||
|
v9fs_marshal(out_sg, 1, offset, 0, fmt, ##args)
|
||||||
|
|
||||||
|
union MsgControl {
|
||||||
|
struct cmsghdr cmsg;
|
||||||
|
char control[CMSG_SPACE(sizeof(int))];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t size;
|
||||||
|
} ProxyHeader;
|
||||||
|
|
||||||
|
#define PROXY_HDR_SZ (sizeof(ProxyHeader))
|
||||||
|
|
||||||
|
enum {
|
||||||
|
T_SUCCESS = 0,
|
||||||
|
T_ERROR,
|
||||||
|
T_OPEN,
|
||||||
|
T_CREATE,
|
||||||
|
T_MKNOD,
|
||||||
|
T_MKDIR,
|
||||||
|
T_SYMLINK,
|
||||||
|
T_LINK,
|
||||||
|
T_LSTAT,
|
||||||
|
T_READLINK,
|
||||||
|
T_STATFS,
|
||||||
|
T_CHMOD,
|
||||||
|
T_CHOWN,
|
||||||
|
T_TRUNCATE,
|
||||||
|
T_UTIME,
|
||||||
|
T_RENAME,
|
||||||
|
T_REMOVE,
|
||||||
|
T_LGETXATTR,
|
||||||
|
T_LLISTXATTR,
|
||||||
|
T_LSETXATTR,
|
||||||
|
T_LREMOVEXATTR,
|
||||||
|
T_GETVERSION,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t st_dev;
|
||||||
|
uint64_t st_ino;
|
||||||
|
uint64_t st_nlink;
|
||||||
|
uint32_t st_mode;
|
||||||
|
uint32_t st_uid;
|
||||||
|
uint32_t st_gid;
|
||||||
|
uint64_t st_rdev;
|
||||||
|
uint64_t st_size;
|
||||||
|
uint64_t st_blksize;
|
||||||
|
uint64_t st_blocks;
|
||||||
|
uint64_t st_atim_sec;
|
||||||
|
uint64_t st_atim_nsec;
|
||||||
|
uint64_t st_mtim_sec;
|
||||||
|
uint64_t st_mtim_nsec;
|
||||||
|
uint64_t st_ctim_sec;
|
||||||
|
uint64_t st_ctim_nsec;
|
||||||
|
} ProxyStat;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t f_type;
|
||||||
|
uint64_t f_bsize;
|
||||||
|
uint64_t f_blocks;
|
||||||
|
uint64_t f_bfree;
|
||||||
|
uint64_t f_bavail;
|
||||||
|
uint64_t f_files;
|
||||||
|
uint64_t f_ffree;
|
||||||
|
uint64_t f_fsid[2];
|
||||||
|
uint64_t f_namelen;
|
||||||
|
uint64_t f_frsize;
|
||||||
|
} ProxyStatFS;
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
@ -8,9 +8,11 @@
|
|||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include "hw/virtio.h"
|
#include "hw/virtio.h"
|
||||||
#include "fsdev/file-op-9p.h"
|
#include "fsdev/file-op-9p.h"
|
||||||
|
#include "fsdev/virtio-9p-marshal.h"
|
||||||
#include "qemu-thread.h"
|
#include "qemu-thread.h"
|
||||||
#include "qemu-coroutine.h"
|
#include "qemu-coroutine.h"
|
||||||
|
|
||||||
|
|
||||||
/* The feature bitmap for virtio 9P */
|
/* The feature bitmap for virtio 9P */
|
||||||
/* The mount point is specified in a config variable */
|
/* The mount point is specified in a config variable */
|
||||||
#define VIRTIO_9P_MOUNT_TAG 0
|
#define VIRTIO_9P_MOUNT_TAG 0
|
||||||
@ -154,40 +156,6 @@ struct V9fsPDU
|
|||||||
|
|
||||||
typedef struct V9fsFidState V9fsFidState;
|
typedef struct V9fsFidState V9fsFidState;
|
||||||
|
|
||||||
typedef struct V9fsString
|
|
||||||
{
|
|
||||||
uint16_t size;
|
|
||||||
char *data;
|
|
||||||
} V9fsString;
|
|
||||||
|
|
||||||
typedef struct V9fsQID
|
|
||||||
{
|
|
||||||
int8_t type;
|
|
||||||
int32_t version;
|
|
||||||
int64_t path;
|
|
||||||
} V9fsQID;
|
|
||||||
|
|
||||||
typedef struct V9fsStat
|
|
||||||
{
|
|
||||||
int16_t size;
|
|
||||||
int16_t type;
|
|
||||||
int32_t dev;
|
|
||||||
V9fsQID qid;
|
|
||||||
int32_t mode;
|
|
||||||
int32_t atime;
|
|
||||||
int32_t mtime;
|
|
||||||
int64_t length;
|
|
||||||
V9fsString name;
|
|
||||||
V9fsString uid;
|
|
||||||
V9fsString gid;
|
|
||||||
V9fsString muid;
|
|
||||||
/* 9p2000.u */
|
|
||||||
V9fsString extension;
|
|
||||||
int32_t n_uid;
|
|
||||||
int32_t n_gid;
|
|
||||||
int32_t n_muid;
|
|
||||||
} V9fsStat;
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
P9_FID_NONE = 0,
|
P9_FID_NONE = 0,
|
||||||
P9_FID_FILE,
|
P9_FID_FILE,
|
||||||
@ -267,29 +235,6 @@ typedef struct V9fsStatState {
|
|||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
} V9fsStatState;
|
} V9fsStatState;
|
||||||
|
|
||||||
typedef struct V9fsStatDotl {
|
|
||||||
uint64_t st_result_mask;
|
|
||||||
V9fsQID qid;
|
|
||||||
uint32_t st_mode;
|
|
||||||
uint32_t st_uid;
|
|
||||||
uint32_t st_gid;
|
|
||||||
uint64_t st_nlink;
|
|
||||||
uint64_t st_rdev;
|
|
||||||
uint64_t st_size;
|
|
||||||
uint64_t st_blksize;
|
|
||||||
uint64_t st_blocks;
|
|
||||||
uint64_t st_atime_sec;
|
|
||||||
uint64_t st_atime_nsec;
|
|
||||||
uint64_t st_mtime_sec;
|
|
||||||
uint64_t st_mtime_nsec;
|
|
||||||
uint64_t st_ctime_sec;
|
|
||||||
uint64_t st_ctime_nsec;
|
|
||||||
uint64_t st_btime_sec;
|
|
||||||
uint64_t st_btime_nsec;
|
|
||||||
uint64_t st_gen;
|
|
||||||
uint64_t st_data_version;
|
|
||||||
} V9fsStatDotl;
|
|
||||||
|
|
||||||
typedef struct V9fsOpenState {
|
typedef struct V9fsOpenState {
|
||||||
V9fsPDU *pdu;
|
V9fsPDU *pdu;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
@ -332,19 +277,6 @@ typedef struct V9fsWriteState {
|
|||||||
int cnt;
|
int cnt;
|
||||||
} V9fsWriteState;
|
} V9fsWriteState;
|
||||||
|
|
||||||
typedef struct V9fsIattr
|
|
||||||
{
|
|
||||||
int32_t valid;
|
|
||||||
int32_t mode;
|
|
||||||
int32_t uid;
|
|
||||||
int32_t gid;
|
|
||||||
int64_t size;
|
|
||||||
int64_t atime_sec;
|
|
||||||
int64_t atime_nsec;
|
|
||||||
int64_t mtime_sec;
|
|
||||||
int64_t mtime_nsec;
|
|
||||||
} V9fsIattr;
|
|
||||||
|
|
||||||
struct virtio_9p_config
|
struct virtio_9p_config
|
||||||
{
|
{
|
||||||
/* number of characters in tag */
|
/* number of characters in tag */
|
||||||
@ -459,14 +391,15 @@ static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu)
|
|||||||
extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
|
extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
|
||||||
extern void virtio_9p_set_fd_limit(void);
|
extern void virtio_9p_set_fd_limit(void);
|
||||||
extern void v9fs_reclaim_fd(V9fsPDU *pdu);
|
extern void v9fs_reclaim_fd(V9fsPDU *pdu);
|
||||||
extern void v9fs_string_init(V9fsString *str);
|
|
||||||
extern void v9fs_string_free(V9fsString *str);
|
|
||||||
extern void v9fs_string_null(V9fsString *str);
|
|
||||||
extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...);
|
|
||||||
extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs);
|
|
||||||
extern void v9fs_path_init(V9fsPath *path);
|
extern void v9fs_path_init(V9fsPath *path);
|
||||||
extern void v9fs_path_free(V9fsPath *path);
|
extern void v9fs_path_free(V9fsPath *path);
|
||||||
extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs);
|
extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs);
|
||||||
extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
|
extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
|
||||||
const char *name, V9fsPath *path);
|
const char *name, V9fsPath *path);
|
||||||
|
|
||||||
|
#define pdu_marshal(pdu, offset, fmt, args...) \
|
||||||
|
v9fs_marshal(pdu->elem.in_sg, pdu->elem.in_num, offset, 1, fmt, ##args)
|
||||||
|
#define pdu_unmarshal(pdu, offset, fmt, args...) \
|
||||||
|
v9fs_unmarshal(pdu->elem.out_sg, pdu->elem.out_num, offset, 1, fmt, ##args)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -211,6 +211,13 @@ QemuOptsList qemu_fsdev_opts = {
|
|||||||
}, {
|
}, {
|
||||||
.name = "readonly",
|
.name = "readonly",
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
|
|
||||||
|
}, {
|
||||||
|
.name = "socket",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
}, {
|
||||||
|
.name = "sock_fd",
|
||||||
|
.type = QEMU_OPT_NUMBER,
|
||||||
},
|
},
|
||||||
|
|
||||||
{ /*End of list */ }
|
{ /*End of list */ }
|
||||||
@ -240,6 +247,12 @@ QemuOptsList qemu_virtfs_opts = {
|
|||||||
}, {
|
}, {
|
||||||
.name = "readonly",
|
.name = "readonly",
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
|
}, {
|
||||||
|
.name = "socket",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
}, {
|
||||||
|
.name = "sock_fd",
|
||||||
|
.type = QEMU_OPT_NUMBER,
|
||||||
},
|
},
|
||||||
|
|
||||||
{ /*End of list */ }
|
{ /*End of list */ }
|
||||||
|
@ -551,19 +551,19 @@ DEFHEADING()
|
|||||||
DEFHEADING(File system options:)
|
DEFHEADING(File system options:)
|
||||||
|
|
||||||
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
|
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
|
||||||
"-fsdev fsdriver,id=id,path=path,[security_model={mapped|passthrough|none}]\n"
|
"-fsdev fsdriver,id=id[,path=path,][security_model={mapped|passthrough|none}]\n"
|
||||||
" [,writeout=immediate][,readonly]\n",
|
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n",
|
||||||
QEMU_ARCH_ALL)
|
QEMU_ARCH_ALL)
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
|
|
||||||
@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}][,readonly]
|
@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}]
|
||||||
@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
|
||||||
@item @var{fsdriver}
|
@item @var{fsdriver}
|
||||||
This option specifies the fs driver backend to use.
|
This option specifies the fs driver backend to use.
|
||||||
Currently "local" and "handle" file system drivers are supported.
|
Currently "local", "handle" and "proxy" file system drivers are supported.
|
||||||
@item id=@var{id}
|
@item id=@var{id}
|
||||||
Specifies identifier for this device
|
Specifies identifier for this device
|
||||||
@item path=@var{path}
|
@item path=@var{path}
|
||||||
@ -580,7 +580,7 @@ file attributes. Directories exported by this security model cannot
|
|||||||
interact with other unix tools. "none" security model is same as
|
interact with other unix tools. "none" security model is same as
|
||||||
passthrough except the sever won't report failures if it fails to
|
passthrough except the sever won't report failures if it fails to
|
||||||
set file attributes like ownership. Security model is mandatory
|
set file attributes like ownership. Security model is mandatory
|
||||||
only for local fsdriver. Other fsdrivers (like handle) don't take
|
only for local fsdriver. Other fsdrivers (like handle, proxy) don't take
|
||||||
security model as a parameter.
|
security model as a parameter.
|
||||||
@item writeout=@var{writeout}
|
@item writeout=@var{writeout}
|
||||||
This is an optional argument. The only supported value is "immediate".
|
This is an optional argument. The only supported value is "immediate".
|
||||||
@ -590,6 +590,13 @@ reported as written by the storage subsystem.
|
|||||||
@item readonly
|
@item readonly
|
||||||
Enables exporting 9p share as a readonly mount for guests. By default
|
Enables exporting 9p share as a readonly mount for guests. By default
|
||||||
read-write access is given.
|
read-write access is given.
|
||||||
|
@item socket=@var{socket}
|
||||||
|
Enables proxy filesystem driver to use passed socket file for communicating
|
||||||
|
with virtfs-proxy-helper
|
||||||
|
@item sock_fd=@var{sock_fd}
|
||||||
|
Enables proxy filesystem driver to use passed socket descriptor for
|
||||||
|
communicating with virtfs-proxy-helper. Usually a helper like libvirt
|
||||||
|
will create socketpair and pass one of the fds as sock_fd
|
||||||
@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".
|
||||||
@ -610,19 +617,19 @@ DEFHEADING(Virtual File system pass-through options:)
|
|||||||
|
|
||||||
DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
|
DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
|
||||||
"-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n"
|
"-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n"
|
||||||
" [,writeout=immediate][,readonly]\n",
|
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\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]
|
@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}]
|
||||||
@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:
|
||||||
@table @option
|
@table @option
|
||||||
@item @var{fsdriver}
|
@item @var{fsdriver}
|
||||||
This option specifies the fs driver backend to use.
|
This option specifies the fs driver backend to use.
|
||||||
Currently "local" and "handle" file system drivers are supported.
|
Currently "local", "handle" and "proxy" file system drivers are supported.
|
||||||
@item id=@var{id}
|
@item id=@var{id}
|
||||||
Specifies identifier for this device
|
Specifies identifier for this device
|
||||||
@item path=@var{path}
|
@item path=@var{path}
|
||||||
@ -639,7 +646,7 @@ file attributes. Directories exported by this security model cannot
|
|||||||
interact with other unix tools. "none" security model is same as
|
interact with other unix tools. "none" security model is same as
|
||||||
passthrough except the sever won't report failures if it fails to
|
passthrough except the sever won't report failures if it fails to
|
||||||
set file attributes like ownership. Security model is mandatory only
|
set file attributes like ownership. Security model is mandatory only
|
||||||
for local fsdriver. Other fsdrivers (like handle) don't take security
|
for local fsdriver. Other fsdrivers (like handle, proxy) don't take security
|
||||||
model as a parameter.
|
model as a parameter.
|
||||||
@item writeout=@var{writeout}
|
@item writeout=@var{writeout}
|
||||||
This is an optional argument. The only supported value is "immediate".
|
This is an optional argument. The only supported value is "immediate".
|
||||||
@ -649,6 +656,13 @@ reported as written by the storage subsystem.
|
|||||||
@item readonly
|
@item readonly
|
||||||
Enables exporting 9p share as a readonly mount for guests. By default
|
Enables exporting 9p share as a readonly mount for guests. By default
|
||||||
read-write access is given.
|
read-write access is given.
|
||||||
|
@item socket=@var{socket}
|
||||||
|
Enables proxy filesystem driver to use passed socket file for
|
||||||
|
communicating with virtfs-proxy-helper. Usually a helper like libvirt
|
||||||
|
will create socketpair and pass one of the fds as sock_fd
|
||||||
|
@item sock_fd
|
||||||
|
Enables proxy filesystem driver to use passed 'sock_fd' as the socket
|
||||||
|
descriptor for interfacing with virtfs-proxy-helper
|
||||||
@end table
|
@end table
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
|
18
vl.c
18
vl.c
@ -2661,7 +2661,7 @@ int main(int argc, char **argv, char **envp)
|
|||||||
case QEMU_OPTION_virtfs: {
|
case QEMU_OPTION_virtfs: {
|
||||||
QemuOpts *fsdev;
|
QemuOpts *fsdev;
|
||||||
QemuOpts *device;
|
QemuOpts *device;
|
||||||
const char *writeout;
|
const char *writeout, *sock_fd, *socket;
|
||||||
|
|
||||||
olist = qemu_find_opts("virtfs");
|
olist = qemu_find_opts("virtfs");
|
||||||
if (!olist) {
|
if (!olist) {
|
||||||
@ -2675,11 +2675,8 @@ int main(int argc, char **argv, char **envp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (qemu_opt_get(opts, "fsdriver") == NULL ||
|
if (qemu_opt_get(opts, "fsdriver") == NULL ||
|
||||||
qemu_opt_get(opts, "mount_tag") == NULL ||
|
qemu_opt_get(opts, "mount_tag") == NULL) {
|
||||||
qemu_opt_get(opts, "path") == NULL) {
|
fprintf(stderr, "Usage: -virtfs fsdriver,mount_tag=tag.\n");
|
||||||
fprintf(stderr, "Usage: -virtfs fsdriver,path=/share_path/,"
|
|
||||||
"[security_model={mapped|passthrough|none}],"
|
|
||||||
"mount_tag=tag.\n");
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
fsdev = qemu_opts_create(qemu_find_opts("fsdev"),
|
fsdev = qemu_opts_create(qemu_find_opts("fsdev"),
|
||||||
@ -2704,6 +2701,14 @@ int main(int argc, char **argv, char **envp)
|
|||||||
qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path"));
|
qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path"));
|
||||||
qemu_opt_set(fsdev, "security_model",
|
qemu_opt_set(fsdev, "security_model",
|
||||||
qemu_opt_get(opts, "security_model"));
|
qemu_opt_get(opts, "security_model"));
|
||||||
|
socket = qemu_opt_get(opts, "socket");
|
||||||
|
if (socket) {
|
||||||
|
qemu_opt_set(fsdev, "socket", socket);
|
||||||
|
}
|
||||||
|
sock_fd = qemu_opt_get(opts, "sock_fd");
|
||||||
|
if (sock_fd) {
|
||||||
|
qemu_opt_set(fsdev, "sock_fd", sock_fd);
|
||||||
|
}
|
||||||
|
|
||||||
qemu_opt_set_bool(fsdev, "readonly",
|
qemu_opt_set_bool(fsdev, "readonly",
|
||||||
qemu_opt_get_bool(opts, "readonly", 0));
|
qemu_opt_get_bool(opts, "readonly", 0));
|
||||||
@ -2725,7 +2730,6 @@ int main(int argc, char **argv, char **envp)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
qemu_opt_set(fsdev, "fsdriver", "synth");
|
qemu_opt_set(fsdev, "fsdriver", "synth");
|
||||||
qemu_opt_set(fsdev, "path", "/"); /* ignored */
|
|
||||||
|
|
||||||
device = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
|
device = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
|
||||||
qemu_opt_set(device, "driver", "virtio-9p-pci");
|
qemu_opt_set(device, "driver", "virtio-9p-pci");
|
||||||
|
Loading…
Reference in New Issue
Block a user