mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/gkurz/tags/9p-next-2019-10-10' into staging
The most notable change is that we now detect cross-device setups in the host since it may cause inode number collision and mayhem in the guest. A new fsdev property is added for the user to choose the appropriate policy to handle that: either remap all inode numbers or fail I/Os to another host device or just print out a warning (default behaviour). This is also my last PR as _active_ maintainer of 9pfs. # gpg: Signature made Thu 10 Oct 2019 12:14:07 BST # gpg: using RSA key B4828BAF943140CEF2A3491071D4D5E5822F73D6 # gpg: Good signature from "Greg Kurz <groug@kaod.org>" [full] # gpg: aka "Gregory Kurz <gregory.kurz@free.fr>" [full] # gpg: aka "[jpeg image of size 3330]" [full] # Primary key fingerprint: B482 8BAF 9431 40CE F2A3 4910 71D4 D5E5 822F 73D6 * remotes/gkurz/tags/9p-next-2019-10-10: MAINTAINERS: Downgrade status of virtio-9p to "Odd Fixes" 9p: Use variable length suffixes for inode remapping 9p: stat_to_qid: implement slow path 9p: Added virtfs option 'multidevs=remap|forbid|warn' 9p: Treat multiple devices on one export as an error fsdev: Add return value to fsdev_throttle_parse_opts() 9p: Simplify error path of v9fs_device_realize_common() 9p: unsigned type for type, version, path Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+1
-1
@@ -1517,7 +1517,7 @@ F: tests/virtio-balloon-test.c
|
||||
|
||||
virtio-9p
|
||||
M: Greg Kurz <groug@kaod.org>
|
||||
S: Supported
|
||||
S: Odd Fixes
|
||||
F: hw/9pfs/
|
||||
X: hw/9pfs/xen-9p*
|
||||
F: fsdev/
|
||||
|
||||
+3
-3
@@ -9,9 +9,9 @@ typedef struct V9fsString
|
||||
|
||||
typedef struct V9fsQID
|
||||
{
|
||||
int8_t type;
|
||||
int32_t version;
|
||||
int64_t path;
|
||||
uint8_t type;
|
||||
uint32_t version;
|
||||
uint64_t path;
|
||||
} V9fsQID;
|
||||
|
||||
typedef struct V9fsStat
|
||||
|
||||
@@ -59,6 +59,11 @@ typedef struct ExtendedOps {
|
||||
#define V9FS_RDONLY 0x00000040
|
||||
#define V9FS_PROXY_SOCK_FD 0x00000080
|
||||
#define V9FS_PROXY_SOCK_NAME 0x00000100
|
||||
/*
|
||||
* multidevs option (either one of the two applies exclusively)
|
||||
*/
|
||||
#define V9FS_REMAP_INODES 0x00000200
|
||||
#define V9FS_FORBID_MULTIDEVS 0x00000400
|
||||
|
||||
#define V9FS_SEC_MASK 0x0000003C
|
||||
|
||||
|
||||
@@ -31,7 +31,9 @@ static QemuOptsList qemu_fsdev_opts = {
|
||||
}, {
|
||||
.name = "readonly",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
|
||||
}, {
|
||||
.name = "multidevs",
|
||||
.type = QEMU_OPT_STRING,
|
||||
}, {
|
||||
.name = "socket",
|
||||
.type = QEMU_OPT_STRING,
|
||||
@@ -75,6 +77,9 @@ static QemuOptsList qemu_virtfs_opts = {
|
||||
}, {
|
||||
.name = "readonly",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
}, {
|
||||
.name = "multidevs",
|
||||
.type = QEMU_OPT_STRING,
|
||||
}, {
|
||||
.name = "socket",
|
||||
.type = QEMU_OPT_STRING,
|
||||
|
||||
@@ -31,7 +31,7 @@ static void fsdev_throttle_write_timer_cb(void *opaque)
|
||||
qemu_co_enter_next(&fst->throttled_reqs[true], NULL);
|
||||
}
|
||||
|
||||
void fsdev_throttle_parse_opts(QemuOpts *opts, FsThrottle *fst, Error **errp)
|
||||
int fsdev_throttle_parse_opts(QemuOpts *opts, FsThrottle *fst, Error **errp)
|
||||
{
|
||||
throttle_config_init(&fst->cfg);
|
||||
fst->cfg.buckets[THROTTLE_BPS_TOTAL].avg =
|
||||
@@ -75,7 +75,7 @@ void fsdev_throttle_parse_opts(QemuOpts *opts, FsThrottle *fst, Error **errp)
|
||||
fst->cfg.op_size =
|
||||
qemu_opt_get_number(opts, "throttling.iops-size", 0);
|
||||
|
||||
throttle_is_valid(&fst->cfg, errp);
|
||||
return throttle_is_valid(&fst->cfg, errp) ? 0 : -1;
|
||||
}
|
||||
|
||||
void fsdev_throttle_init(FsThrottle *fst)
|
||||
|
||||
@@ -26,7 +26,7 @@ typedef struct FsThrottle {
|
||||
CoQueue throttled_reqs[2];
|
||||
} FsThrottle;
|
||||
|
||||
void fsdev_throttle_parse_opts(QemuOpts *, FsThrottle *, Error **);
|
||||
int fsdev_throttle_parse_opts(QemuOpts *, FsThrottle *, Error **);
|
||||
|
||||
void fsdev_throttle_init(FsThrottle *);
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ static FsDriverTable FsDrivers[] = {
|
||||
"writeout",
|
||||
"fmode",
|
||||
"dmode",
|
||||
"multidevs",
|
||||
"throttling.bps-total",
|
||||
"throttling.bps-read",
|
||||
"throttling.bps-write",
|
||||
|
||||
+26
-2
@@ -1465,6 +1465,10 @@ static void local_cleanup(FsContext *ctx)
|
||||
{
|
||||
LocalData *data = ctx->private;
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
close(data->mountfd);
|
||||
g_free(data);
|
||||
}
|
||||
@@ -1479,6 +1483,7 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
|
||||
{
|
||||
const char *sec_model = qemu_opt_get(opts, "security_model");
|
||||
const char *path = qemu_opt_get(opts, "path");
|
||||
const char *multidevs = qemu_opt_get(opts, "multidevs");
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!sec_model) {
|
||||
@@ -1502,13 +1507,32 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (multidevs) {
|
||||
if (!strcmp(multidevs, "remap")) {
|
||||
fse->export_flags &= ~V9FS_FORBID_MULTIDEVS;
|
||||
fse->export_flags |= V9FS_REMAP_INODES;
|
||||
} else if (!strcmp(multidevs, "forbid")) {
|
||||
fse->export_flags &= ~V9FS_REMAP_INODES;
|
||||
fse->export_flags |= V9FS_FORBID_MULTIDEVS;
|
||||
} else if (!strcmp(multidevs, "warn")) {
|
||||
fse->export_flags &= ~V9FS_FORBID_MULTIDEVS;
|
||||
fse->export_flags &= ~V9FS_REMAP_INODES;
|
||||
} else {
|
||||
error_setg(&local_err, "invalid multidevs property '%s'",
|
||||
multidevs);
|
||||
error_append_hint(&local_err, "Valid options are: multidevs="
|
||||
"[remap|forbid|warn]\n");
|
||||
error_propagate(errp, local_err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!path) {
|
||||
error_setg(errp, "path property not set");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fsdev_throttle_parse_opts(opts, &fse->fst, &local_err);
|
||||
if (local_err) {
|
||||
if (fsdev_throttle_parse_opts(opts, &fse->fst, &local_err)) {
|
||||
error_propagate_prepend(errp, local_err,
|
||||
"invalid throttle configuration: ");
|
||||
return -1;
|
||||
|
||||
@@ -1185,6 +1185,10 @@ static void proxy_cleanup(FsContext *ctx)
|
||||
{
|
||||
V9fsProxy *proxy = ctx->private;
|
||||
|
||||
if (!proxy) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_free(proxy->out_iovec.iov_base);
|
||||
g_free(proxy->in_iovec.iov_base);
|
||||
if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
|
||||
|
||||
+493
-41
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@
|
||||
#include "fsdev/9p-iov-marshal.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/coroutine.h"
|
||||
#include "qemu/qht.h"
|
||||
|
||||
enum {
|
||||
P9_TLERROR = 6,
|
||||
@@ -235,6 +236,58 @@ struct V9fsFidState
|
||||
V9fsFidState *rclm_lst;
|
||||
};
|
||||
|
||||
typedef enum AffixType_t {
|
||||
AffixType_Prefix,
|
||||
AffixType_Suffix, /* A.k.a. postfix. */
|
||||
} AffixType_t;
|
||||
|
||||
/**
|
||||
* @brief Unique affix of variable length.
|
||||
*
|
||||
* An affix is (currently) either a suffix or a prefix, which is either
|
||||
* going to be prepended (prefix) or appended (suffix) with some other
|
||||
* number for the goal to generate unique numbers. Accordingly the
|
||||
* suffixes (or prefixes) we generate @b must all have the mathematical
|
||||
* property of being suffix-free (or prefix-free in case of prefixes)
|
||||
* so that no matter what number we concatenate the affix with, that we
|
||||
* always reliably get unique numbers as result after concatenation.
|
||||
*/
|
||||
typedef struct VariLenAffix {
|
||||
AffixType_t type; /* Whether this affix is a suffix or a prefix. */
|
||||
uint64_t value; /* Actual numerical value of this affix. */
|
||||
/*
|
||||
* Lenght of the affix, that is how many (of the lowest) bits of @c value
|
||||
* must be used for appending/prepending this affix to its final resulting,
|
||||
* unique number.
|
||||
*/
|
||||
int bits;
|
||||
} VariLenAffix;
|
||||
|
||||
/* See qid_inode_prefix_hash_bits(). */
|
||||
typedef struct {
|
||||
dev_t dev; /* FS device on host. */
|
||||
/*
|
||||
* How many (high) bits of the original inode number shall be used for
|
||||
* hashing.
|
||||
*/
|
||||
int prefix_bits;
|
||||
} QpdEntry;
|
||||
|
||||
/* QID path prefix entry, see stat_to_qid */
|
||||
typedef struct {
|
||||
dev_t dev;
|
||||
uint16_t ino_prefix;
|
||||
uint32_t qp_affix_index;
|
||||
VariLenAffix qp_affix;
|
||||
} QppEntry;
|
||||
|
||||
/* QID path full entry, as above */
|
||||
typedef struct {
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
uint64_t path;
|
||||
} QpfEntry;
|
||||
|
||||
struct V9fsState
|
||||
{
|
||||
QLIST_HEAD(, V9fsPDU) free_list;
|
||||
@@ -256,6 +309,13 @@ struct V9fsState
|
||||
Error *migration_blocker;
|
||||
V9fsConf fsconf;
|
||||
V9fsQID root_qid;
|
||||
dev_t dev_id;
|
||||
struct qht qpd_table;
|
||||
struct qht qpp_table;
|
||||
struct qht qpf_table;
|
||||
uint64_t qp_ndevices; /* Amount of entries in qpd_table. */
|
||||
uint16_t qp_affix_next;
|
||||
uint64_t qp_fullpath_next;
|
||||
};
|
||||
|
||||
/* 9p2000.L open flags */
|
||||
|
||||
@@ -6,7 +6,7 @@ v9fs_rerror(uint16_t tag, uint8_t id, int err) "tag %d id %d err %d"
|
||||
v9fs_version(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s"
|
||||
v9fs_version_return(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s"
|
||||
v9fs_attach(uint16_t tag, uint8_t id, int32_t fid, int32_t afid, char* uname, char* aname) "tag %u id %u fid %d afid %d uname %s aname %s"
|
||||
v9fs_attach_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d type %d version %d path %"PRId64
|
||||
v9fs_attach_return(uint16_t tag, uint8_t id, uint8_t type, uint32_t version, uint64_t path) "tag %u id %u type %u version %u path %"PRIu64
|
||||
v9fs_stat(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
|
||||
v9fs_stat_return(uint16_t tag, uint8_t id, int32_t mode, int32_t atime, int32_t mtime, int64_t length) "tag %d id %d stat={mode %d atime %d mtime %d length %"PRId64"}"
|
||||
v9fs_getattr(uint16_t tag, uint8_t id, int32_t fid, uint64_t request_mask) "tag %d id %d fid %d request_mask %"PRIu64
|
||||
@@ -14,9 +14,9 @@ v9fs_getattr_return(uint16_t tag, uint8_t id, uint64_t result_mask, uint32_t mod
|
||||
v9fs_walk(uint16_t tag, uint8_t id, int32_t fid, int32_t newfid, uint16_t nwnames) "tag %d id %d fid %d newfid %d nwnames %d"
|
||||
v9fs_walk_return(uint16_t tag, uint8_t id, uint16_t nwnames, void* qids) "tag %d id %d nwnames %d qids %p"
|
||||
v9fs_open(uint16_t tag, uint8_t id, int32_t fid, int32_t mode) "tag %d id %d fid %d mode %d"
|
||||
v9fs_open_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d"
|
||||
v9fs_open_return(uint16_t tag, uint8_t id, uint8_t type, uint32_t version, uint64_t path, int iounit) "tag %u id %u qid={type %u version %u path %"PRIu64"} iounit %d"
|
||||
v9fs_lcreate(uint16_t tag, uint8_t id, int32_t dfid, int32_t flags, int32_t mode, uint32_t gid) "tag %d id %d dfid %d flags %d mode %d gid %u"
|
||||
v9fs_lcreate_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int32_t iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d"
|
||||
v9fs_lcreate_return(uint16_t tag, uint8_t id, uint8_t type, uint32_t version, uint64_t path, int32_t iounit) "tag %u id %u qid={type %u version %u path %"PRIu64"} iounit %d"
|
||||
v9fs_fsync(uint16_t tag, uint8_t id, int32_t fid, int datasync) "tag %d id %d fid %d datasync %d"
|
||||
v9fs_clunk(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
|
||||
v9fs_read(uint16_t tag, uint8_t id, int32_t fid, uint64_t off, uint32_t max_count) "tag %d id %d fid %d off %"PRIu64" max_count %u"
|
||||
@@ -26,21 +26,21 @@ v9fs_readdir_return(uint16_t tag, uint8_t id, uint32_t count, ssize_t retval) "t
|
||||
v9fs_write(uint16_t tag, uint8_t id, int32_t fid, uint64_t off, uint32_t count, int cnt) "tag %d id %d fid %d off %"PRIu64" count %u cnt %d"
|
||||
v9fs_write_return(uint16_t tag, uint8_t id, int32_t total, ssize_t err) "tag %d id %d total %d err %zd"
|
||||
v9fs_create(uint16_t tag, uint8_t id, int32_t fid, char* name, int32_t perm, int8_t mode) "tag %d id %d fid %d name %s perm %d mode %d"
|
||||
v9fs_create_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d"
|
||||
v9fs_create_return(uint16_t tag, uint8_t id, uint8_t type, uint32_t version, uint64_t path, int iounit) "tag %u id %u qid={type %u version %u path %"PRIu64"} iounit %d"
|
||||
v9fs_symlink(uint16_t tag, uint8_t id, int32_t fid, char* name, char* symname, uint32_t gid) "tag %d id %d fid %d name %s symname %s gid %u"
|
||||
v9fs_symlink_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d qid={type %d version %d path %"PRId64"}"
|
||||
v9fs_symlink_return(uint16_t tag, uint8_t id, uint8_t type, uint32_t version, uint64_t path) "tag %u id %u qid={type %u version %u path %"PRIu64"}"
|
||||
v9fs_flush(uint16_t tag, uint8_t id, int16_t flush_tag) "tag %d id %d flush_tag %d"
|
||||
v9fs_link(uint16_t tag, uint8_t id, int32_t dfid, int32_t oldfid, char* name) "tag %d id %d dfid %d oldfid %d name %s"
|
||||
v9fs_remove(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
|
||||
v9fs_wstat(uint16_t tag, uint8_t id, int32_t fid, int32_t mode, int32_t atime, int32_t mtime) "tag %u id %u fid %d stat={mode %d atime %d mtime %d}"
|
||||
v9fs_mknod(uint16_t tag, uint8_t id, int32_t fid, int mode, int major, int minor) "tag %d id %d fid %d mode %d major %d minor %d"
|
||||
v9fs_mknod_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d qid={type %d version %d path %"PRId64"}"
|
||||
v9fs_mknod_return(uint16_t tag, uint8_t id, uint8_t type, uint32_t version, uint64_t path) "tag %u id %u qid={type %u version %u path %"PRIu64"}"
|
||||
v9fs_lock(uint16_t tag, uint8_t id, int32_t fid, uint8_t type, uint64_t start, uint64_t length) "tag %d id %d fid %d type %d start %"PRIu64" length %"PRIu64
|
||||
v9fs_lock_return(uint16_t tag, uint8_t id, int8_t status) "tag %d id %d status %d"
|
||||
v9fs_getlock(uint16_t tag, uint8_t id, int32_t fid, uint8_t type, uint64_t start, uint64_t length)"tag %d id %d fid %d type %d start %"PRIu64" length %"PRIu64
|
||||
v9fs_getlock_return(uint16_t tag, uint8_t id, uint8_t type, uint64_t start, uint64_t length, uint32_t proc_id) "tag %d id %d type %d start %"PRIu64" length %"PRIu64" proc_id %u"
|
||||
v9fs_mkdir(uint16_t tag, uint8_t id, int32_t fid, char* name, int mode, uint32_t gid) "tag %u id %u fid %d name %s mode %d gid %u"
|
||||
v9fs_mkdir_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int err) "tag %u id %u qid={type %d version %d path %"PRId64"} err %d"
|
||||
v9fs_mkdir_return(uint16_t tag, uint8_t id, uint8_t type, uint32_t version, uint64_t path, int err) "tag %u id %u qid={type %u version %u path %"PRIu64"} err %d"
|
||||
v9fs_xattrwalk(uint16_t tag, uint8_t id, int32_t fid, int32_t newfid, char* name) "tag %d id %d fid %d newfid %d name %s"
|
||||
v9fs_xattrwalk_return(uint16_t tag, uint8_t id, int64_t size) "tag %d id %d size %"PRId64
|
||||
v9fs_xattrcreate(uint16_t tag, uint8_t id, int32_t fid, char* name, uint64_t size, int flags) "tag %d id %d fid %d name %s size %"PRIu64" flags %d"
|
||||
|
||||
+24
-2
@@ -1339,7 +1339,7 @@ ETEXI
|
||||
|
||||
DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
|
||||
"-virtfs local,path=path,mount_tag=tag,security_model=mapped-xattr|mapped-file|passthrough|none\n"
|
||||
" [,id=id][,writeout=immediate][,readonly][,fmode=fmode][,dmode=dmode]\n"
|
||||
" [,id=id][,writeout=immediate][,readonly][,fmode=fmode][,dmode=dmode][,multidevs=remap|forbid|warn]\n"
|
||||
"-virtfs proxy,mount_tag=tag,socket=socket[,id=id][,writeout=immediate][,readonly]\n"
|
||||
"-virtfs proxy,mount_tag=tag,sock_fd=sock_fd[,id=id][,writeout=immediate][,readonly]\n"
|
||||
"-virtfs synth,mount_tag=tag[,id=id][,readonly]\n",
|
||||
@@ -1347,7 +1347,7 @@ DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
|
||||
|
||||
STEXI
|
||||
|
||||
@item -virtfs local,path=@var{path},mount_tag=@var{mount_tag} ,security_model=@var{security_model}[,writeout=@var{writeout}][,readonly] [,fmode=@var{fmode}][,dmode=@var{dmode}]
|
||||
@item -virtfs local,path=@var{path},mount_tag=@var{mount_tag} ,security_model=@var{security_model}[,writeout=@var{writeout}][,readonly] [,fmode=@var{fmode}][,dmode=@var{dmode}][,multidevs=@var{multidevs}]
|
||||
@itemx -virtfs proxy,socket=@var{socket},mount_tag=@var{mount_tag} [,writeout=@var{writeout}][,readonly]
|
||||
@itemx -virtfs proxy,sock_fd=@var{sock_fd},mount_tag=@var{mount_tag} [,writeout=@var{writeout}][,readonly]
|
||||
@itemx -virtfs synth,mount_tag=@var{mount_tag}
|
||||
@@ -1403,6 +1403,28 @@ Specifies the default mode for newly created directories on the host. Works
|
||||
only with security models "mapped-xattr" and "mapped-file".
|
||||
@item mount_tag=@var{mount_tag}
|
||||
Specifies the tag name to be used by the guest to mount this export point.
|
||||
@item multidevs=@var{multidevs}
|
||||
Specifies how to deal with multiple devices being shared with a 9p export.
|
||||
Supported behaviours are either "remap", "forbid" or "warn". The latter is
|
||||
the default behaviour on which virtfs 9p expects only one device to be
|
||||
shared with the same export, and if more than one device is shared and
|
||||
accessed via the same 9p export then only a warning message is logged
|
||||
(once) by qemu on host side. In order to avoid file ID collisions on guest
|
||||
you should either create a separate virtfs export for each device to be
|
||||
shared with guests (recommended way) or you might use "remap" instead which
|
||||
allows you to share multiple devices with only one export instead, which is
|
||||
achieved by remapping the original inode numbers from host to guest in a
|
||||
way that would prevent such collisions. Remapping inodes in such use cases
|
||||
is required because the original device IDs from host are never passed and
|
||||
exposed on guest. Instead all files of an export shared with virtfs always
|
||||
share the same device id on guest. So two files with identical inode
|
||||
numbers but from actually different devices on host would otherwise cause a
|
||||
file ID collision and hence potential misbehaviours on guest. "forbid" on
|
||||
the other hand assumes like "warn" that only one device is shared by the
|
||||
same export, however it will not only log a warning message but also
|
||||
deny access to additional devices on guest. Note though that "forbid" does
|
||||
currently not block all possible file access operations (e.g. readdir()
|
||||
would still return entries from other devices).
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
|
||||
@@ -3335,7 +3335,8 @@ int main(int argc, char **argv, char **envp)
|
||||
case QEMU_OPTION_virtfs: {
|
||||
QemuOpts *fsdev;
|
||||
QemuOpts *device;
|
||||
const char *writeout, *sock_fd, *socket, *path, *security_model;
|
||||
const char *writeout, *sock_fd, *socket, *path, *security_model,
|
||||
*multidevs;
|
||||
|
||||
olist = qemu_find_opts("virtfs");
|
||||
if (!olist) {
|
||||
@@ -3395,6 +3396,10 @@ int main(int argc, char **argv, char **envp)
|
||||
qemu_opt_set_bool(fsdev, "readonly",
|
||||
qemu_opt_get_bool(opts, "readonly", 0),
|
||||
&error_abort);
|
||||
multidevs = qemu_opt_get(opts, "multidevs");
|
||||
if (multidevs) {
|
||||
qemu_opt_set(fsdev, "multidevs", multidevs, &error_abort);
|
||||
}
|
||||
device = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
|
||||
&error_abort);
|
||||
qemu_opt_set(device, "driver", "virtio-9p-pci", &error_abort);
|
||||
|
||||
Reference in New Issue
Block a user