Merge remote-tracking branch 'aneesh/for-upstream-6' into staging

Conflicts:
	trace-events
This commit is contained in:
Anthony Liguori 2011-10-20 08:42:08 -05:00
commit 1f99b94932
22 changed files with 857 additions and 888 deletions

View file

@ -305,7 +305,7 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
9pfs-nested-$(CONFIG_VIRTFS) = virtio-9p.o virtio-9p-debug.o
9pfs-nested-$(CONFIG_VIRTFS) = virtio-9p.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o

33
configure vendored
View file

@ -2556,6 +2556,31 @@ EOF
fi
fi
##########################################
# check if we have open_by_handle_at
open_by_hande_at=no
cat > $TMPC << EOF
#include <fcntl.h>
int main(void) { struct file_handle *fh; open_by_handle_at(0, fh, 0); }
EOF
if compile_prog "" "" ; then
open_by_handle_at=yes
fi
########################################
# check if we have linux/magic.h
linux_magic_h=no
cat > $TMPC << EOF
#include <linux/magic.h>
int main(void) {
}
EOF
if compile_prog "" "" ; then
linux_magic_h=yes
fi
##########################################
# End of CC checks
# After here, no more $cc or $ld runs
@ -3035,6 +3060,14 @@ if test "$ucontext_coroutine" = "yes" ; then
echo "CONFIG_UCONTEXT_COROUTINE=y" >> $config_host_mak
fi
if test "$open_by_handle_at" = "yes" ; then
echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak
fi
if test "$linux_magic_h" = "yes" ; then
echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak
fi
# USB host support
case "$usb" in
linux)

View file

@ -23,23 +23,6 @@
#define SM_LOCAL_MODE_BITS 0600
#define SM_LOCAL_DIR_MODE_BITS 0700
typedef enum
{
/*
* Server will try to set uid/gid.
* On failure ignore the error.
*/
SM_NONE = 0,
/*
* uid/gid set on fileserver files
*/
SM_PASSTHROUGH = 1,
/*
* uid/gid part of xattr
*/
SM_MAPPED,
} SecModel;
typedef struct FsCred
{
uid_t fc_uid;
@ -49,17 +32,41 @@ typedef struct FsCred
} FsCred;
struct xattr_operations;
struct FsContext;
struct V9fsPath;
/* FsContext flag values */
#define PATHNAME_FSCONTEXT 0x1
typedef struct extended_ops {
int (*get_st_gen)(struct FsContext *, struct V9fsPath *,
mode_t, uint64_t *);
} extended_ops;
/* export flags */
#define V9FS_IMMEDIATE_WRITEOUT 0x00000001
#define V9FS_PATHNAME_FSCONTEXT 0x00000002
/*
* uid/gid set on fileserver files
*/
#define V9FS_SM_PASSTHROUGH 0x00000004
/*
* uid/gid part of xattr
*/
#define V9FS_SM_MAPPED 0x00000008
/*
* Server will try to set uid/gid.
* On failure ignore the error.
*/
#define V9FS_SM_NONE 0x00000010
#define V9FS_SEC_MASK 0x0000001C
typedef struct FsContext
{
int flags;
char *fs_root;
SecModel fs_sm;
uid_t uid;
char *fs_root;
int export_flags;
struct xattr_operations **xops;
struct extended_ops exops;
/* fs driver specific data */
void *private;
} FsContext;

View file

@ -18,46 +18,55 @@
#include "qemu-common.h"
#include "qemu-config.h"
static QTAILQ_HEAD(FsTypeEntry_head, FsTypeListEntry) fstype_entries =
QTAILQ_HEAD_INITIALIZER(fstype_entries);
static QTAILQ_HEAD(FsDriverEntry_head, FsDriverListEntry) fsdriver_entries =
QTAILQ_HEAD_INITIALIZER(fsdriver_entries);
static FsTypeTable FsTypes[] = {
static FsDriverTable FsDrivers[] = {
{ .name = "local", .ops = &local_ops},
{ .name = "handle", .ops = &handle_ops},
};
int qemu_fsdev_add(QemuOpts *opts)
{
struct FsTypeListEntry *fsle;
struct FsDriverListEntry *fsle;
int i;
const char *fsdev_id = qemu_opts_id(opts);
const char *fstype = qemu_opt_get(opts, "fstype");
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");
if (!fsdev_id) {
fprintf(stderr, "fsdev: No id specified\n");
return -1;
}
if (fstype) {
for (i = 0; i < ARRAY_SIZE(FsTypes); i++) {
if (strcmp(FsTypes[i].name, fstype) == 0) {
if (fsdriver) {
for (i = 0; i < ARRAY_SIZE(FsDrivers); i++) {
if (strcmp(FsDrivers[i].name, fsdriver) == 0) {
break;
}
}
if (i == ARRAY_SIZE(FsTypes)) {
fprintf(stderr, "fsdev: fstype %s not found\n", fstype);
if (i == ARRAY_SIZE(FsDrivers)) {
fprintf(stderr, "fsdev: fsdriver %s not found\n", fsdriver);
return -1;
}
} else {
fprintf(stderr, "fsdev: No fstype specified\n");
fprintf(stderr, "fsdev: No fsdriver specified\n");
return -1;
}
if (!sec_model) {
fprintf(stderr, "fsdev: No security_model specified.\n");
if (!strcmp(fsdriver, "local") && !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(fsdriver, "local") && sec_model) {
fprintf(stderr, "only local fs driver needs security model\n");
return -1;
}
@ -70,20 +79,40 @@ int qemu_fsdev_add(QemuOpts *opts)
fsle->fse.fsdev_id = g_strdup(fsdev_id);
fsle->fse.path = g_strdup(path);
fsle->fse.security_model = g_strdup(sec_model);
fsle->fse.ops = FsTypes[i].ops;
fsle->fse.ops = FsDrivers[i].ops;
fsle->fse.export_flags = 0;
if (writeout) {
if (!strcmp(writeout, "immediate")) {
fsle->fse.export_flags |= V9FS_IMMEDIATE_WRITEOUT;
}
}
QTAILQ_INSERT_TAIL(&fstype_entries, fsle, next);
if (strcmp(fsdriver, "local")) {
goto done;
}
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;
}
done:
QTAILQ_INSERT_TAIL(&fsdriver_entries, fsle, next);
return 0;
}
FsTypeEntry *get_fsdev_fsentry(char *id)
FsDriverEntry *get_fsdev_fsentry(char *id)
{
if (id) {
struct FsTypeListEntry *fsle;
struct FsDriverListEntry *fsle;
QTAILQ_FOREACH(fsle, &fstype_entries, next) {
QTAILQ_FOREACH(fsle, &fsdriver_entries, next) {
if (strcmp(fsle->fse.fsdev_id, id) == 0) {
return &fsle->fse;
}

View file

@ -29,28 +29,28 @@
* -----------------
* etc
*/
typedef struct FsTypeTable {
typedef struct FsDriverTable {
const char *name;
FileOperations *ops;
} FsTypeTable;
} FsDriverTable;
/*
* Structure to store the various fsdev's passed through command line.
*/
typedef struct FsTypeEntry {
typedef struct FsDriverEntry {
char *fsdev_id;
char *path;
char *security_model;
int export_flags;
FileOperations *ops;
} FsTypeEntry;
} FsDriverEntry;
typedef struct FsTypeListEntry {
FsTypeEntry fse;
QTAILQ_ENTRY(FsTypeListEntry) next;
} FsTypeListEntry;
typedef struct FsDriverListEntry {
FsDriverEntry fse;
QTAILQ_ENTRY(FsDriverListEntry) next;
} FsDriverListEntry;
int qemu_fsdev_add(QemuOpts *opts);
FsTypeEntry *get_fsdev_fsentry(char *id);
FsDriverEntry *get_fsdev_fsentry(char *id);
extern FileOperations local_ops;
extern FileOperations handle_ops;
#endif

View file

@ -17,6 +17,30 @@
#include "qemu-coroutine.h"
#include "virtio-9p-coth.h"
int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode,
V9fsStatDotl *v9stat)
{
int err = 0;
V9fsState *s = pdu->s;
if (v9fs_request_cancelled(pdu)) {
return -EINTR;
}
if (s->ctx.exops.get_st_gen) {
v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
err = s->ctx.exops.get_st_gen(&s->ctx, path, st_mode,
&v9stat->st_gen);
if (err < 0) {
err = -errno;
}
});
v9fs_path_unlock(s);
}
return err;
}
int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
{
int err;

View file

@ -323,7 +323,7 @@ int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath,
int err;
V9fsState *s = pdu->s;
if (s->ctx.flags & PATHNAME_FSCONTEXT) {
if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
if (err < 0) {
err = -errno;

View file

@ -101,4 +101,7 @@ extern int v9fs_co_preadv(V9fsPDU *, V9fsFidState *,
struct iovec *, int, int64_t);
extern int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *,
const char *, V9fsPath *);
extern int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t,
V9fsStatDotl *v9stat);
#endif

View file

@ -1,646 +0,0 @@
/*
* Virtio 9p PDU debug
*
* 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 "hw/virtio.h"
#include "hw/pc.h"
#include "virtio-9p.h"
#include "virtio-9p-debug.h"
#define BUG_ON(cond) assert(!(cond))
static FILE *llogfile;
static struct iovec *get_sg(V9fsPDU *pdu, int rx)
{
if (rx) {
return pdu->elem.in_sg;
}
return pdu->elem.out_sg;
}
static int get_sg_count(V9fsPDU *pdu, int rx)
{
if (rx) {
return pdu->elem.in_num;
}
return pdu->elem.out_num;
}
static void pprint_int8(V9fsPDU *pdu, int rx, size_t *offsetp,
const char *name)
{
size_t copied;
int count = get_sg_count(pdu, rx);
size_t offset = *offsetp;
struct iovec *sg = get_sg(pdu, rx);
int8_t value;
copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
BUG_ON(copied != sizeof(value));
offset += sizeof(value);
fprintf(llogfile, "%s=0x%x", name, value);
*offsetp = offset;
}
static void pprint_int16(V9fsPDU *pdu, int rx, size_t *offsetp,
const char *name)
{
size_t copied;
int count = get_sg_count(pdu, rx);
struct iovec *sg = get_sg(pdu, rx);
size_t offset = *offsetp;
int16_t value;
copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
BUG_ON(copied != sizeof(value));
offset += sizeof(value);
fprintf(llogfile, "%s=0x%x", name, value);
*offsetp = offset;
}
static void pprint_int32(V9fsPDU *pdu, int rx, size_t *offsetp,
const char *name)
{
size_t copied;
int count = get_sg_count(pdu, rx);
struct iovec *sg = get_sg(pdu, rx);
size_t offset = *offsetp;
int32_t value;
copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
BUG_ON(copied != sizeof(value));
offset += sizeof(value);
fprintf(llogfile, "%s=0x%x", name, value);
*offsetp = offset;
}
static void pprint_int64(V9fsPDU *pdu, int rx, size_t *offsetp,
const char *name)
{
size_t copied;
int count = get_sg_count(pdu, rx);
struct iovec *sg = get_sg(pdu, rx);
size_t offset = *offsetp;
int64_t value;
copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
BUG_ON(copied != sizeof(value));
offset += sizeof(value);
fprintf(llogfile, "%s=0x%" PRIx64, name, value);
*offsetp = offset;
}
static void pprint_str(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
{
int sg_count = get_sg_count(pdu, rx);
struct iovec *sg = get_sg(pdu, rx);
size_t offset = *offsetp;
uint16_t tmp_size, size;
size_t result;
size_t copied = 0;
int i = 0;
/* get the size */
copied = do_pdu_unpack(&tmp_size, sg, sg_count, offset, sizeof(tmp_size));
BUG_ON(copied != sizeof(tmp_size));
size = le16_to_cpupu(&tmp_size);
offset += copied;
fprintf(llogfile, "%s=", name);
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);
result = fwrite(sg[i].iov_base + offset, 1, len, llogfile);
BUG_ON(result != len);
size -= len;
copied += len;
if (size) {
offset = 0;
continue;
}
}
}
*offsetp += copied;
}
static void pprint_qid(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
{
fprintf(llogfile, "%s={", name);
pprint_int8(pdu, rx, offsetp, "type");
pprint_int32(pdu, rx, offsetp, ", version");
pprint_int64(pdu, rx, offsetp, ", path");
fprintf(llogfile, "}");
}
static void pprint_stat(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
{
fprintf(llogfile, "%s={", name);
pprint_int16(pdu, rx, offsetp, "size");
pprint_int16(pdu, rx, offsetp, ", type");
pprint_int32(pdu, rx, offsetp, ", dev");
pprint_qid(pdu, rx, offsetp, ", qid");
pprint_int32(pdu, rx, offsetp, ", mode");
pprint_int32(pdu, rx, offsetp, ", atime");
pprint_int32(pdu, rx, offsetp, ", mtime");
pprint_int64(pdu, rx, offsetp, ", length");
pprint_str(pdu, rx, offsetp, ", name");
pprint_str(pdu, rx, offsetp, ", uid");
pprint_str(pdu, rx, offsetp, ", gid");
pprint_str(pdu, rx, offsetp, ", muid");
pprint_str(pdu, rx, offsetp, ", extension");
pprint_int32(pdu, rx, offsetp, ", uid");
pprint_int32(pdu, rx, offsetp, ", gid");
pprint_int32(pdu, rx, offsetp, ", muid");
fprintf(llogfile, "}");
}
static void pprint_stat_dotl(V9fsPDU *pdu, int rx, size_t *offsetp,
const char *name)
{
fprintf(llogfile, "%s={", name);
pprint_qid(pdu, rx, offsetp, "qid");
pprint_int32(pdu, rx, offsetp, ", st_mode");
pprint_int64(pdu, rx, offsetp, ", st_nlink");
pprint_int32(pdu, rx, offsetp, ", st_uid");
pprint_int32(pdu, rx, offsetp, ", st_gid");
pprint_int64(pdu, rx, offsetp, ", st_rdev");
pprint_int64(pdu, rx, offsetp, ", st_size");
pprint_int64(pdu, rx, offsetp, ", st_blksize");
pprint_int64(pdu, rx, offsetp, ", st_blocks");
pprint_int64(pdu, rx, offsetp, ", atime");
pprint_int64(pdu, rx, offsetp, ", atime_nsec");
pprint_int64(pdu, rx, offsetp, ", mtime");
pprint_int64(pdu, rx, offsetp, ", mtime_nsec");
pprint_int64(pdu, rx, offsetp, ", ctime");
pprint_int64(pdu, rx, offsetp, ", ctime_nsec");
fprintf(llogfile, "}");
}
static void pprint_strs(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
{
int sg_count = get_sg_count(pdu, rx);
struct iovec *sg = get_sg(pdu, rx);
size_t offset = *offsetp;
uint16_t tmp_count, count, i;
size_t copied = 0;
fprintf(llogfile, "%s={", name);
/* Get the count */
copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count));
BUG_ON(copied != sizeof(tmp_count));
count = le16_to_cpupu(&tmp_count);
offset += copied;
for (i = 0; i < count; i++) {
char str[512];
if (i) {
fprintf(llogfile, ", ");
}
snprintf(str, sizeof(str), "[%d]", i);
pprint_str(pdu, rx, &offset, str);
}
fprintf(llogfile, "}");
*offsetp = offset;
}
static void pprint_qids(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
{
int sg_count = get_sg_count(pdu, rx);
struct iovec *sg = get_sg(pdu, rx);
size_t offset = *offsetp;
uint16_t tmp_count, count, i;
size_t copied = 0;
fprintf(llogfile, "%s={", name);
copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count));
BUG_ON(copied != sizeof(tmp_count));
count = le16_to_cpupu(&tmp_count);
offset += copied;
for (i = 0; i < count; i++) {
char str[512];
if (i) {
fprintf(llogfile, ", ");
}
snprintf(str, sizeof(str), "[%d]", i);
pprint_qid(pdu, rx, &offset, str);
}
fprintf(llogfile, "}");
*offsetp = offset;
}
static void pprint_sg(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
{
struct iovec *sg = get_sg(pdu, rx);
unsigned int count;
int i;
if (rx) {
count = pdu->elem.in_num;
} else {
count = pdu->elem.out_num;
}
fprintf(llogfile, "%s={", name);
for (i = 0; i < count; i++) {
if (i) {
fprintf(llogfile, ", ");
}
fprintf(llogfile, "(%p, 0x%zx)", sg[i].iov_base, sg[i].iov_len);
}
fprintf(llogfile, "}");
}
/* FIXME: read from a directory fid returns serialized stat_t's */
#ifdef DEBUG_DATA
static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
{
struct iovec *sg = get_sg(pdu, rx);
size_t offset = *offsetp;
unsigned int count;
int32_t size;
int total, i, j;
ssize_t len;
if (rx) {
count = pdu->elem.in_num;
} else {
count = pdu->elem.out_num;
}
BUG_ON((offset + sizeof(size)) > sg[0].iov_len);
memcpy(&size, sg[0].iov_base + offset, sizeof(size));
offset += sizeof(size);
fprintf(llogfile, "size: %x\n", size);
sg[0].iov_base += 11; /* skip header */
sg[0].iov_len -= 11;
total = 0;
for (i = 0; i < count; i++) {
total += sg[i].iov_len;
if (total >= size) {
/* trim sg list so writev does the right thing */
sg[i].iov_len -= (total - size);
i++;
break;
}
}
fprintf(llogfile, "%s={\"", name);
fflush(llogfile);
for (j = 0; j < i; j++) {
if (j) {
fprintf(llogfile, "\", \"");
fflush(llogfile);
}
do {
len = writev(fileno(llogfile), &sg[j], 1);
} while (len == -1 && errno == EINTR);
fprintf(llogfile, "len == %ld: %m\n", len);
BUG_ON(len != sg[j].iov_len);
}
fprintf(llogfile, "\"}");
sg[0].iov_base -= 11;
sg[0].iov_len += 11;
}
#endif
void pprint_pdu(V9fsPDU *pdu)
{
size_t offset = 7;
if (llogfile == NULL) {
llogfile = fopen("/tmp/pdu.log", "w");
}
BUG_ON(!llogfile);
switch (pdu->id) {
case P9_TREADDIR:
fprintf(llogfile, "TREADDIR: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_int64(pdu, 0, &offset, ", initial offset");
pprint_int32(pdu, 0, &offset, ", max count");
break;
case P9_RREADDIR:
fprintf(llogfile, "RREADDIR: (");
pprint_int32(pdu, 1, &offset, "count");
#ifdef DEBUG_DATA
pprint_data(pdu, 1, &offset, ", data");
#endif
break;
case P9_TMKDIR:
fprintf(llogfile, "TMKDIR: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_str(pdu, 0, &offset, "name");
pprint_int32(pdu, 0, &offset, "mode");
pprint_int32(pdu, 0, &offset, "gid");
break;
case P9_RMKDIR:
fprintf(llogfile, "RMKDIR: (");
pprint_qid(pdu, 0, &offset, "qid");
break;
case P9_TVERSION:
fprintf(llogfile, "TVERSION: (");
pprint_int32(pdu, 0, &offset, "msize");
pprint_str(pdu, 0, &offset, ", version");
break;
case P9_RVERSION:
fprintf(llogfile, "RVERSION: (");
pprint_int32(pdu, 1, &offset, "msize");
pprint_str(pdu, 1, &offset, ", version");
break;
case P9_TGETATTR:
fprintf(llogfile, "TGETATTR: (");
pprint_int32(pdu, 0, &offset, "fid");
break;
case P9_RGETATTR:
fprintf(llogfile, "RGETATTR: (");
pprint_stat_dotl(pdu, 1, &offset, "getattr");
break;
case P9_TAUTH:
fprintf(llogfile, "TAUTH: (");
pprint_int32(pdu, 0, &offset, "afid");
pprint_str(pdu, 0, &offset, ", uname");
pprint_str(pdu, 0, &offset, ", aname");
pprint_int32(pdu, 0, &offset, ", n_uname");
break;
case P9_RAUTH:
fprintf(llogfile, "RAUTH: (");
pprint_qid(pdu, 1, &offset, "qid");
break;
case P9_TATTACH:
fprintf(llogfile, "TATTACH: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_int32(pdu, 0, &offset, ", afid");
pprint_str(pdu, 0, &offset, ", uname");
pprint_str(pdu, 0, &offset, ", aname");
pprint_int32(pdu, 0, &offset, ", n_uname");
break;
case P9_RATTACH:
fprintf(llogfile, "RATTACH: (");
pprint_qid(pdu, 1, &offset, "qid");
break;
case P9_TERROR:
fprintf(llogfile, "TERROR: (");
break;
case P9_RERROR:
fprintf(llogfile, "RERROR: (");
pprint_str(pdu, 1, &offset, "ename");
pprint_int32(pdu, 1, &offset, ", ecode");
break;
case P9_TFLUSH:
fprintf(llogfile, "TFLUSH: (");
pprint_int16(pdu, 0, &offset, "oldtag");
break;
case P9_RFLUSH:
fprintf(llogfile, "RFLUSH: (");
break;
case P9_TWALK:
fprintf(llogfile, "TWALK: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_int32(pdu, 0, &offset, ", newfid");
pprint_strs(pdu, 0, &offset, ", wnames");
break;
case P9_RWALK:
fprintf(llogfile, "RWALK: (");
pprint_qids(pdu, 1, &offset, "wqids");
break;
case P9_TOPEN:
fprintf(llogfile, "TOPEN: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_int8(pdu, 0, &offset, ", mode");
break;
case P9_ROPEN:
fprintf(llogfile, "ROPEN: (");
pprint_qid(pdu, 1, &offset, "qid");
pprint_int32(pdu, 1, &offset, ", iounit");
break;
case P9_TCREATE:
fprintf(llogfile, "TCREATE: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_str(pdu, 0, &offset, ", name");
pprint_int32(pdu, 0, &offset, ", perm");
pprint_int8(pdu, 0, &offset, ", mode");
pprint_str(pdu, 0, &offset, ", extension");
break;
case P9_RCREATE:
fprintf(llogfile, "RCREATE: (");
pprint_qid(pdu, 1, &offset, "qid");
pprint_int32(pdu, 1, &offset, ", iounit");
break;
case P9_TSYMLINK:
fprintf(llogfile, "TSYMLINK: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_str(pdu, 0, &offset, ", name");
pprint_str(pdu, 0, &offset, ", symname");
pprint_int32(pdu, 0, &offset, ", gid");
break;
case P9_RSYMLINK:
fprintf(llogfile, "RSYMLINK: (");
pprint_qid(pdu, 1, &offset, "qid");
break;
case P9_TLCREATE:
fprintf(llogfile, "TLCREATE: (");
pprint_int32(pdu, 0, &offset, "dfid");
pprint_str(pdu, 0, &offset, ", name");
pprint_int32(pdu, 0, &offset, ", flags");
pprint_int32(pdu, 0, &offset, ", mode");
pprint_int32(pdu, 0, &offset, ", gid");
break;
case P9_RLCREATE:
fprintf(llogfile, "RLCREATE: (");
pprint_qid(pdu, 1, &offset, "qid");
pprint_int32(pdu, 1, &offset, ", iounit");
break;
case P9_TMKNOD:
fprintf(llogfile, "TMKNOD: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_str(pdu, 0, &offset, "name");
pprint_int32(pdu, 0, &offset, "mode");
pprint_int32(pdu, 0, &offset, "major");
pprint_int32(pdu, 0, &offset, "minor");
pprint_int32(pdu, 0, &offset, "gid");
break;
case P9_RMKNOD:
fprintf(llogfile, "RMKNOD: )");
pprint_qid(pdu, 0, &offset, "qid");
break;
case P9_TREADLINK:
fprintf(llogfile, "TREADLINK: (");
pprint_int32(pdu, 0, &offset, "fid");
break;
case P9_RREADLINK:
fprintf(llogfile, "RREADLINK: (");
pprint_str(pdu, 0, &offset, "target");
break;
case P9_TREAD:
fprintf(llogfile, "TREAD: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_int64(pdu, 0, &offset, ", offset");
pprint_int32(pdu, 0, &offset, ", count");
pprint_sg(pdu, 0, &offset, ", sg");
break;
case P9_RREAD:
fprintf(llogfile, "RREAD: (");
pprint_int32(pdu, 1, &offset, "count");
pprint_sg(pdu, 1, &offset, ", sg");
offset = 7;
#ifdef DEBUG_DATA
pprint_data(pdu, 1, &offset, ", data");
#endif
break;
case P9_TWRITE:
fprintf(llogfile, "TWRITE: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_int64(pdu, 0, &offset, ", offset");
pprint_int32(pdu, 0, &offset, ", count");
break;
case P9_RWRITE:
fprintf(llogfile, "RWRITE: (");
pprint_int32(pdu, 1, &offset, "count");
break;
case P9_TCLUNK:
fprintf(llogfile, "TCLUNK: (");
pprint_int32(pdu, 0, &offset, "fid");
break;
case P9_RCLUNK:
fprintf(llogfile, "RCLUNK: (");
break;
case P9_TFSYNC:
fprintf(llogfile, "TFSYNC: (");
pprint_int32(pdu, 0, &offset, "fid");
break;
case P9_RFSYNC:
fprintf(llogfile, "RFSYNC: (");
break;
case P9_TLINK:
fprintf(llogfile, "TLINK: (");
pprint_int32(pdu, 0, &offset, "dfid");
pprint_int32(pdu, 0, &offset, ", fid");
pprint_str(pdu, 0, &offset, ", newpath");
break;
case P9_RLINK:
fprintf(llogfile, "RLINK: (");
break;
case P9_TREMOVE:
fprintf(llogfile, "TREMOVE: (");
pprint_int32(pdu, 0, &offset, "fid");
break;
case P9_RREMOVE:
fprintf(llogfile, "RREMOVE: (");
break;
case P9_TSTAT:
fprintf(llogfile, "TSTAT: (");
pprint_int32(pdu, 0, &offset, "fid");
break;
case P9_RSTAT:
fprintf(llogfile, "RSTAT: (");
offset += 2; /* ignored */
pprint_stat(pdu, 1, &offset, "stat");
break;
case P9_TWSTAT:
fprintf(llogfile, "TWSTAT: (");
pprint_int32(pdu, 0, &offset, "fid");
offset += 2; /* ignored */
pprint_stat(pdu, 0, &offset, ", stat");
break;
case P9_RWSTAT:
fprintf(llogfile, "RWSTAT: (");
break;
case P9_TXATTRWALK:
fprintf(llogfile, "TXATTRWALK: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_int32(pdu, 0, &offset, ", newfid");
pprint_str(pdu, 0, &offset, ", xattr name");
break;
case P9_RXATTRWALK:
fprintf(llogfile, "RXATTRWALK: (");
pprint_int64(pdu, 1, &offset, "xattrsize");
case P9_TXATTRCREATE:
fprintf(llogfile, "TXATTRCREATE: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_str(pdu, 0, &offset, ", name");
pprint_int64(pdu, 0, &offset, ", xattrsize");
pprint_int32(pdu, 0, &offset, ", flags");
break;
case P9_RXATTRCREATE:
fprintf(llogfile, "RXATTRCREATE: (");
break;
case P9_TLOCK:
fprintf(llogfile, "TLOCK: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_int8(pdu, 0, &offset, ", type");
pprint_int32(pdu, 0, &offset, ", flags");
pprint_int64(pdu, 0, &offset, ", start");
pprint_int64(pdu, 0, &offset, ", length");
pprint_int32(pdu, 0, &offset, ", proc_id");
pprint_str(pdu, 0, &offset, ", client_id");
break;
case P9_RLOCK:
fprintf(llogfile, "RLOCK: (");
pprint_int8(pdu, 0, &offset, "status");
break;
case P9_TGETLOCK:
fprintf(llogfile, "TGETLOCK: (");
pprint_int32(pdu, 0, &offset, "fid");
pprint_int8(pdu, 0, &offset, ", type");
pprint_int64(pdu, 0, &offset, ", start");
pprint_int64(pdu, 0, &offset, ", length");
pprint_int32(pdu, 0, &offset, ", proc_id");
pprint_str(pdu, 0, &offset, ", client_id");
break;
case P9_RGETLOCK:
fprintf(llogfile, "RGETLOCK: (");
pprint_int8(pdu, 0, &offset, "type");
pprint_int64(pdu, 0, &offset, ", start");
pprint_int64(pdu, 0, &offset, ", length");
pprint_int32(pdu, 0, &offset, ", proc_id");
pprint_str(pdu, 0, &offset, ", client_id");
break;
default:
fprintf(llogfile, "unknown(%d): (", pdu->id);
break;
}
fprintf(llogfile, ")\n");
/* Flush the log message out */
fflush(llogfile);
}

View file

@ -1,6 +0,0 @@
#ifndef _QEMU_VIRTIO_9P_DEBUG_H
#define _QEMU_VIRTIO_9P_DEBUG_H
void pprint_pdu(V9fsPDU *pdu);
#endif

View file

@ -49,7 +49,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
V9fsState *s;
int i, len;
struct stat stat;
FsTypeEntry *fse;
FsDriverEntry *fse;
V9fsPath path;
s = (V9fsState *)virtio_common_init("virtio-9p",
VIRTIO_ID_9P,
@ -82,55 +83,33 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
exit(1);
}
if (!strcmp(fse->security_model, "passthrough")) {
/* Files on the Fileserver set to client user credentials */
s->ctx.fs_sm = SM_PASSTHROUGH;
s->ctx.xops = passthrough_xattr_ops;
} else if (!strcmp(fse->security_model, "mapped")) {
/* Files on the fileserver are set to QEMU credentials.
* Client user credentials are saved in extended attributes.
*/
s->ctx.fs_sm = SM_MAPPED;
s->ctx.xops = mapped_xattr_ops;
} else if (!strcmp(fse->security_model, "none")) {
/*
* Files on the fileserver are set to QEMU credentials.
*/
s->ctx.fs_sm = SM_NONE;
s->ctx.xops = none_xattr_ops;
} else {
fprintf(stderr, "Default to security_model=none. You may want"
" enable advanced security model using "
"security option:\n\t security_model=passthrough\n\t "
"security_model=mapped\n");
s->ctx.fs_sm = SM_NONE;
s->ctx.xops = none_xattr_ops;
}
if (lstat(fse->path, &stat)) {
fprintf(stderr, "share path %s does not exist\n", fse->path);
exit(1);
} else if (!S_ISDIR(stat.st_mode)) {
fprintf(stderr, "share path %s is not a directory\n", fse->path);
exit(1);
}
s->ctx.export_flags = fse->export_flags;
s->ctx.fs_root = g_strdup(fse->path);
s->ctx.exops.get_st_gen = NULL;
if (fse->export_flags & V9FS_SM_PASSTHROUGH) {
s->ctx.xops = passthrough_xattr_ops;
} else if (fse->export_flags & V9FS_SM_MAPPED) {
s->ctx.xops = mapped_xattr_ops;
} else if (fse->export_flags & V9FS_SM_NONE) {
s->ctx.xops = none_xattr_ops;
}
len = strlen(conf->tag);
if (len > MAX_TAG_LEN) {
len = MAX_TAG_LEN;
fprintf(stderr, "mount tag '%s' (%d bytes) is longer than "
"maximum (%d bytes)", conf->tag, len, MAX_TAG_LEN);
exit(1);
}
/* s->tag is non-NULL terminated string */
s->tag = g_malloc(len);
memcpy(s->tag, conf->tag, len);
s->tag_len = len;
s->ctx.uid = -1;
s->ctx.flags = 0;
s->ops = fse->ops;
s->vdev.get_features = virtio_9p_get_features;
s->config_size = sizeof(struct virtio_9p_config) +
s->tag_len;
s->config_size = sizeof(struct virtio_9p_config) + s->tag_len;
s->vdev.get_config = virtio_9p_get_config;
s->fid_list = NULL;
qemu_co_rwlock_init(&s->rename_lock);
@ -144,6 +123,27 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
fprintf(stderr, "worker thread initialization failed\n");
exit(1);
}
/*
* Check details of export path, We need to use fs driver
* call back to do that. Since we are in the init path, we don't
* use co-routines here.
*/
v9fs_path_init(&path);
if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) {
fprintf(stderr,
"error in converting name to path %s", strerror(errno));
exit(1);
}
if (s->ops->lstat(&s->ctx, &path, &stat)) {
fprintf(stderr, "share path %s does not exist\n", fse->path);
exit(1);
} else if (!S_ISDIR(stat.st_mode)) {
fprintf(stderr, "share path %s is not a directory\n", fse->path);
exit(1);
}
v9fs_path_free(&path);
return &s->vdev;
}
@ -169,6 +169,8 @@ static PCIDeviceInfo virtio_9p_info = {
.revision = VIRTIO_PCI_ABI_VERSION,
.class_id = 0x2,
.qdev.props = (Property[]) {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),

View file

@ -21,19 +21,48 @@
#include <sys/un.h>
#include <attr/xattr.h>
#include <unistd.h>
#include <linux/fs.h>
#ifdef CONFIG_LINUX_MAGIC_H
#include <linux/magic.h>
#endif
#include <sys/ioctl.h>
#ifndef XFS_SUPER_MAGIC
#define XFS_SUPER_MAGIC 0x58465342
#endif
#ifndef EXT2_SUPER_MAGIC
#define EXT2_SUPER_MAGIC 0xEF53
#endif
#ifndef REISERFS_SUPER_MAGIC
#define REISERFS_SUPER_MAGIC 0x52654973
#endif
#ifndef BTRFS_SUPER_MAGIC
#define BTRFS_SUPER_MAGIC 0x9123683E
#endif
struct handle_data {
int mountfd;
int handle_bytes;
};
#if __GLIBC__ <= 2 && __GLIBC_MINOR__ < 14
#ifdef CONFIG_OPEN_BY_HANDLE
static inline int name_to_handle(int dirfd, const char *name,
struct file_handle *fh, int *mnt_id, int flags)
{
return name_to_handle_at(dirfd, name, fh, mnt_id, flags);
}
static inline int open_by_handle(int mountfd, const char *fh, int flags)
{
return open_by_handle_at(mountfd, (struct file_handle *)fh, flags);
}
#else
struct file_handle {
unsigned int handle_bytes;
int handle_type;
unsigned char handle[0];
unsigned int handle_bytes;
int handle_type;
unsigned char handle[0];
};
#endif
#ifndef AT_EMPTY_PATH
#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
@ -42,28 +71,6 @@ struct file_handle {
#define O_PATH 010000000
#endif
#ifndef __NR_name_to_handle_at
#if defined(__i386__)
#define __NR_name_to_handle_at 341
#define __NR_open_by_handle_at 342
#elif defined(__x86_64__)
#define __NR_name_to_handle_at 303
#define __NR_open_by_handle_at 304
#endif
#endif
#ifdef __NR_name_to_handle_at
static inline int name_to_handle(int dirfd, const char *name,
struct file_handle *fh, int *mnt_id, int flags)
{
return syscall(__NR_name_to_handle_at, dirfd, name, fh, mnt_id, flags);
}
static inline int open_by_handle(int mountfd, const char *fh, int flags)
{
return syscall(__NR_open_by_handle_at, mountfd, fh, flags);
}
#else
static inline int name_to_handle(int dirfd, const char *name,
struct file_handle *fh, int *mnt_id, int flags)
{
@ -192,16 +199,29 @@ static ssize_t handle_preadv(FsContext *ctx, int fd, const struct iovec *iov,
static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
int iovcnt, off_t offset)
{
ssize_t ret;
#ifdef CONFIG_PREADV
return pwritev(fd, iov, iovcnt, offset);
ret = pwritev(fd, iov, iovcnt, offset);
#else
int err = lseek(fd, offset, SEEK_SET);
if (err == -1) {
return err;
} else {
return writev(fd, iov, iovcnt);
ret = writev(fd, iov, iovcnt);
}
#endif
#ifdef CONFIG_SYNC_FILE_RANGE
if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
/*
* Initiate a writeback. This is not a data integrity sync.
* We want to ensure that we don't leave dirty pages in the cache
* after write when writeout=immediate is sepcified.
*/
sync_file_range(fd, offset, ret,
SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
}
#endif
return ret;
}
static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
@ -367,7 +387,9 @@ static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
const struct timespec *buf)
{
int fd, ret;
int ret;
#ifdef CONFIG_UTIMENSAT
int fd;
struct handle_data *data = (struct handle_data *)ctx->private;
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
@ -376,6 +398,10 @@ static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
}
ret = futimens(fd, buf);
close(fd);
#else
ret = -1;
errno = ENOSYS;
#endif
return ret;
}
@ -546,16 +572,50 @@ static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
return ret;
}
static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
mode_t st_mode, uint64_t *st_gen)
{
int err, fd;
/*
* Do not try to open special files like device nodes, fifos etc
* We can get fd for regular files and directories only
*/
if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
return 0;
}
fd = handle_open(ctx, path, O_RDONLY);
if (fd < 0) {
return fd;
}
err = ioctl(fd, FS_IOC_GETVERSION, st_gen);
handle_close(ctx, fd);
return err;
}
static int handle_init(FsContext *ctx)
{
int ret, mnt_id;
struct statfs stbuf;
struct file_handle fh;
struct handle_data *data = g_malloc(sizeof(struct handle_data));
data->mountfd = open(ctx->fs_root, O_DIRECTORY);
if (data->mountfd < 0) {
ret = data->mountfd;
goto err_out;
}
ret = statfs(ctx->fs_root, &stbuf);
if (!ret) {
switch (stbuf.f_type) {
case EXT2_SUPER_MAGIC:
case BTRFS_SUPER_MAGIC:
case REISERFS_SUPER_MAGIC:
case XFS_SUPER_MAGIC:
ctx->exops.get_st_gen = handle_ioc_getversion;
break;
}
}
memset(&fh, 0, sizeof(struct file_handle));
ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0);
if (ret && errno == EOVERFLOW) {

View file

@ -20,6 +20,24 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <attr/xattr.h>
#include <linux/fs.h>
#ifdef CONFIG_LINUX_MAGIC_H
#include <linux/magic.h>
#endif
#include <sys/ioctl.h>
#ifndef XFS_SUPER_MAGIC
#define XFS_SUPER_MAGIC 0x58465342
#endif
#ifndef EXT2_SUPER_MAGIC
#define EXT2_SUPER_MAGIC 0xEF53
#endif
#ifndef REISERFS_SUPER_MAGIC
#define REISERFS_SUPER_MAGIC 0x52654973
#endif
#ifndef BTRFS_SUPER_MAGIC
#define BTRFS_SUPER_MAGIC 0x9123683E
#endif
static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
{
@ -31,7 +49,7 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
if (err) {
return err;
}
if (fs_ctx->fs_sm == SM_MAPPED) {
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
/* Actual credentials are part of extended attrs */
uid_t tmp_uid;
gid_t tmp_gid;
@ -106,7 +124,7 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
* If we fail to change ownership and if we are
* using security model none. Ignore the error
*/
if (fs_ctx->fs_sm != SM_NONE) {
if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
return -1;
}
}
@ -120,7 +138,7 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
char buffer[PATH_MAX];
char *path = fs_path->data;
if (fs_ctx->fs_sm == SM_MAPPED) {
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
int fd;
fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
if (fd == -1) {
@ -131,8 +149,8 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
} while (tsize == -1 && errno == EINTR);
close(fd);
return tsize;
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz);
}
return tsize;
@ -203,16 +221,30 @@ static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
int iovcnt, off_t offset)
{
ssize_t ret
;
#ifdef CONFIG_PREADV
return pwritev(fd, iov, iovcnt, offset);
ret = pwritev(fd, iov, iovcnt, offset);
#else
int err = lseek(fd, offset, SEEK_SET);
if (err == -1) {
return err;
} else {
return writev(fd, iov, iovcnt);
ret = writev(fd, iov, iovcnt);
}
#endif
#ifdef CONFIG_SYNC_FILE_RANGE
if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
/*
* Initiate a writeback. This is not a data integrity sync.
* We want to ensure that we don't leave dirty pages in the cache
* after write when writeout=immediate is sepcified.
*/
sync_file_range(fd, offset, ret,
SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
}
#endif
return ret;
}
static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
@ -220,10 +252,10 @@ static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
char buffer[PATH_MAX];
char *path = fs_path->data;
if (fs_ctx->fs_sm == SM_MAPPED) {
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
}
return -1;
@ -243,7 +275,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
path = fullname.data;
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
err = mknod(rpath(fs_ctx, path, buffer),
SM_LOCAL_MODE_BITS|S_IFREG, 0);
if (err == -1) {
@ -254,8 +286,8 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
serrno = errno;
goto err_end;
}
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
credp->fc_rdev);
if (err == -1) {
@ -291,7 +323,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
path = fullname.data;
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
if (err == -1) {
goto out;
@ -302,8 +334,8 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
serrno = errno;
goto err_end;
}
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
if (err == -1) {
goto out;
@ -331,7 +363,7 @@ static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
if (err) {
return err;
}
if (fs_ctx->fs_sm == SM_MAPPED) {
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
/* Actual credentials are part of extended attrs */
uid_t tmp_uid;
gid_t tmp_gid;
@ -369,7 +401,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
path = fullname.data;
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
if (fd == -1) {
err = fd;
@ -382,8 +414,8 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
serrno = errno;
goto err_end;
}
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
if (fd == -1) {
err = fd;
@ -422,7 +454,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
newpath = fullname.data;
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
int fd;
ssize_t oldpath_size, write_size;
fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR,
@ -451,8 +483,8 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
serrno = errno;
goto err_end;
}
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
if (err) {
goto out;
@ -464,7 +496,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
* If we fail to change ownership and if we are
* using security model none. Ignore the error
*/
if (fs_ctx->fs_sm != SM_NONE) {
if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
serrno = errno;
goto err_end;
} else
@ -519,13 +551,13 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
char *path = fs_path->data;
if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
(fs_ctx->fs_sm == SM_PASSTHROUGH)) {
(fs_ctx->export_flags & V9FS_SM_PASSTHROUGH)) {
return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
credp->fc_gid);
} else if (fs_ctx->fs_sm == SM_MAPPED) {
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
credp->fc_gid);
}
@ -645,10 +677,44 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
return ret;
}
static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
mode_t st_mode, uint64_t *st_gen)
{
int err, fd;
/*
* Do not try to open special files like device nodes, fifos etc
* We can get fd for regular files and directories only
*/
if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
return 0;
}
fd = local_open(ctx, path, O_RDONLY);
if (fd < 0) {
return fd;
}
err = ioctl(fd, FS_IOC_GETVERSION, st_gen);
local_close(ctx, fd);
return err;
}
static int local_init(FsContext *ctx)
{
ctx->flags |= PATHNAME_FSCONTEXT;
return 0;
int err;
struct statfs stbuf;
ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
err = statfs(ctx->fs_root, &stbuf);
if (!err) {
switch (stbuf.f_type) {
case EXT2_SUPER_MAGIC:
case BTRFS_SUPER_MAGIC:
case REISERFS_SUPER_MAGIC:
case XFS_SUPER_MAGIC:
ctx->exops.get_st_gen = local_ioc_getversion;
break;
}
}
return err;
}
FileOperations local_ops = {

View file

@ -17,11 +17,10 @@
#include "hw/virtio-pci.h"
#include "virtio-9p.h"
#include "fsdev/qemu-fsdev.h"
#include "virtio-9p-debug.h"
#include "virtio-9p-xattr.h"
#include "virtio-9p-coth.h"
#include "trace.h"
int debug_9p_pdu;
int open_fd_hw;
int total_open_fd;
static int open_fd_rc;
@ -72,6 +71,55 @@ static int omode_to_uflags(int8_t mode)
return ret;
}
static int dotl_to_at_flags(int flags)
{
int rflags = 0;
if (flags & P9_DOTL_AT_REMOVEDIR) {
rflags |= AT_REMOVEDIR;
}
return rflags;
}
struct dotl_openflag_map {
int dotl_flag;
int open_flag;
};
static int dotl_to_open_flags(int flags)
{
int i;
/*
* We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
* and P9_DOTL_NOACCESS
*/
int oflags = flags & O_ACCMODE;
struct dotl_openflag_map dotl_oflag_map[] = {
{ P9_DOTL_CREATE, O_CREAT },
{ P9_DOTL_EXCL, O_EXCL },
{ P9_DOTL_NOCTTY , O_NOCTTY },
{ P9_DOTL_TRUNC, O_TRUNC },
{ P9_DOTL_APPEND, O_APPEND },
{ P9_DOTL_NONBLOCK, O_NONBLOCK } ,
{ P9_DOTL_DSYNC, O_DSYNC },
{ P9_DOTL_FASYNC, FASYNC },
{ P9_DOTL_DIRECT, O_DIRECT },
{ P9_DOTL_LARGEFILE, O_LARGEFILE },
{ P9_DOTL_DIRECTORY, O_DIRECTORY },
{ P9_DOTL_NOFOLLOW, O_NOFOLLOW },
{ P9_DOTL_NOATIME, O_NOATIME },
{ P9_DOTL_SYNC, O_SYNC },
};
for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
if (flags & dotl_oflag_map[i].dotl_flag) {
oflags |= dotl_oflag_map[i].open_flag;
}
}
return oflags;
}
void cred_init(FsCred *credp)
{
credp->fc_uid = -1;
@ -80,6 +128,21 @@ void cred_init(FsCred *credp)
credp->fc_rdev = -1;
}
static int get_dotl_openflags(V9fsState *s, int oflags)
{
int flags;
/*
* Filter the client open flags
*/
flags = dotl_to_open_flags(oflags);
flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
/*
* Ignore direct disk access hint until the server supports it.
*/
flags &= ~O_DIRECT;
return flags;
}
void v9fs_string_init(V9fsString *str)
{
str->data = NULL;
@ -621,9 +684,6 @@ static V9fsPDU *alloc_pdu(V9fsState *s)
static void free_pdu(V9fsState *s, V9fsPDU *pdu)
{
if (pdu) {
if (debug_9p_pdu) {
pprint_pdu(pdu);
}
/*
* Cancelled pdu are added back to the freelist
* by flush request .
@ -909,6 +969,7 @@ static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
if (s->proto_version == V9FS_PROTO_2000L) {
id = P9_RLERROR;
}
trace_complete_pdu(pdu->tag, pdu->id, err); /* Trace ERROR */
}
/* fill out the header */
@ -1218,6 +1279,7 @@ static void v9fs_version(void *opaque)
size_t offset = 7;
pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
if (!strcmp(version.data, "9P2000.u")) {
s->proto_version = V9FS_PROTO_2000U;
@ -1228,6 +1290,8 @@ static void v9fs_version(void *opaque)
}
offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data);
complete_pdu(s, pdu, offset);
v9fs_string_free(&version);
@ -1246,6 +1310,7 @@ static void v9fs_attach(void *opaque)
ssize_t err;
pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data);
fidp = alloc_fid(s, fid);
if (fidp == NULL) {
@ -1270,6 +1335,8 @@ static void v9fs_attach(void *opaque)
out:
put_fid(pdu, fidp);
out_nofid:
trace_v9fs_attach_return(pdu->tag, pdu->id,
qid.type, qid.version, qid.path);
complete_pdu(s, pdu, err);
v9fs_string_free(&uname);
v9fs_string_free(&aname);
@ -1287,6 +1354,7 @@ static void v9fs_stat(void *opaque)
V9fsState *s = pdu->s;
pdu_unmarshal(pdu, offset, "d", &fid);
trace_v9fs_stat(pdu->tag, pdu->id, fid);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
@ -1307,6 +1375,9 @@ static void v9fs_stat(void *opaque)
out:
put_fid(pdu, fidp);
out_nofid:
trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
v9stat.atime, v9stat.mtime, v9stat.length);
complete_pdu(s, pdu, err);
}
@ -1323,6 +1394,7 @@ static void v9fs_getattr(void *opaque)
V9fsState *s = pdu->s;
pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
@ -1338,11 +1410,24 @@ static void v9fs_getattr(void *opaque)
goto out;
}
stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
/* fill st_gen if requested and supported by underlying fs */
if (request_mask & P9_STATS_GEN) {
retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
if (retval < 0) {
goto out;
}
v9stat_dotl.st_result_mask |= P9_STATS_GEN;
}
retval = offset;
retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
out:
put_fid(pdu, fidp);
out_nofid:
trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
v9stat_dotl.st_mode, v9stat_dotl.st_uid,
v9stat_dotl.st_gid);
complete_pdu(s, pdu, retval);
}
@ -1470,6 +1555,8 @@ static void v9fs_walk(void *opaque)
offset += pdu_unmarshal(pdu, offset, "ddw", &fid,
&newfid, &nwnames);
trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
if (nwnames && nwnames <= P9_MAXWELEM) {
wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
qids = g_malloc0(sizeof(qids[0]) * nwnames);
@ -1526,6 +1613,7 @@ out:
v9fs_path_free(&dpath);
v9fs_path_free(&path);
out_nofid:
trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
complete_pdu(s, pdu, err);
if (nwnames && nwnames <= P9_MAXWELEM) {
for (name_idx = 0; name_idx < nwnames; name_idx++) {
@ -1576,6 +1664,8 @@ static void v9fs_open(void *opaque)
} else {
pdu_unmarshal(pdu, offset, "db", &fid, &mode);
}
trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
@ -1598,10 +1688,7 @@ static void v9fs_open(void *opaque)
err = offset;
} else {
if (s->proto_version == V9FS_PROTO_2000L) {
flags = mode;
flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
/* Ignore direct disk access hint until the server supports it. */
flags &= ~O_DIRECT;
flags = get_dotl_openflags(s, mode);
} else {
flags = omode_to_uflags(mode);
}
@ -1625,6 +1712,8 @@ static void v9fs_open(void *opaque)
out:
put_fid(pdu, fidp);
out_nofid:
trace_v9fs_open_return(pdu->tag, pdu->id,
qid.type, qid.version, qid.path, iounit);
complete_pdu(s, pdu, err);
}
@ -1643,6 +1732,7 @@ static void v9fs_lcreate(void *opaque)
pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
&mode, &gid);
trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
fidp = get_fid(pdu, dfid);
if (fidp == NULL) {
@ -1650,8 +1740,7 @@ static void v9fs_lcreate(void *opaque)
goto out_nofid;
}
/* Ignore direct disk access hint until the server supports it. */
flags &= ~O_DIRECT;
flags = get_dotl_openflags(pdu->s, flags);
err = v9fs_co_open2(pdu, fidp, &name, gid,
flags | O_CREAT, mode, &stbuf);
if (err < 0) {
@ -1673,6 +1762,8 @@ static void v9fs_lcreate(void *opaque)
out:
put_fid(pdu, fidp);
out_nofid:
trace_v9fs_lcreate_return(pdu->tag, pdu->id,
qid.type, qid.version, qid.path, iounit);
complete_pdu(pdu->s, pdu, err);
v9fs_string_free(&name);
}
@ -1688,6 +1779,8 @@ static void v9fs_fsync(void *opaque)
V9fsState *s = pdu->s;
pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
@ -1712,6 +1805,7 @@ static void v9fs_clunk(void *opaque)
V9fsState *s = pdu->s;
pdu_unmarshal(pdu, offset, "d", &fid);
trace_v9fs_clunk(pdu->tag, pdu->id, fid);
fidp = clunk_fid(s, fid);
if (fidp == NULL) {
@ -1828,6 +1922,7 @@ static void v9fs_read(void *opaque)
V9fsState *s = pdu->s;
pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
@ -1886,6 +1981,7 @@ static void v9fs_read(void *opaque)
out:
put_fid(pdu, fidp);
out_nofid:
trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
complete_pdu(s, pdu, err);
}
@ -1970,6 +2066,8 @@ static void v9fs_readdir(void *opaque)
pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
retval = -EINVAL;
@ -1995,6 +2093,7 @@ static void v9fs_readdir(void *opaque)
out:
put_fid(pdu, fidp);
out_nofid:
trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
complete_pdu(s, pdu, retval);
}
@ -2059,6 +2158,7 @@ static void v9fs_write(void *opaque)
V9fsState *s = pdu->s;
pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, cnt);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
@ -2105,6 +2205,7 @@ static void v9fs_write(void *opaque)
out:
put_fid(pdu, fidp);
out_nofid:
trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
complete_pdu(s, pdu, err);
}
@ -2129,6 +2230,8 @@ static void v9fs_create(void *opaque)
pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
&perm, &mode, &extension);
trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -EINVAL;
@ -2262,6 +2365,8 @@ static void v9fs_create(void *opaque)
out:
put_fid(pdu, fidp);
out_nofid:
trace_v9fs_create_return(pdu->tag, pdu->id,
qid.type, qid.version, qid.path, iounit);
complete_pdu(pdu->s, pdu, err);
v9fs_string_free(&name);
v9fs_string_free(&extension);
@ -2282,6 +2387,7 @@ static void v9fs_symlink(void *opaque)
size_t offset = 7;
pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid);
dfidp = get_fid(pdu, dfid);
if (dfidp == NULL) {
@ -2298,6 +2404,8 @@ static void v9fs_symlink(void *opaque)
out:
put_fid(pdu, dfidp);
out_nofid:
trace_v9fs_symlink_return(pdu->tag, pdu->id,
qid.type, qid.version, qid.path);
complete_pdu(pdu->s, pdu, err);
v9fs_string_free(&name);
v9fs_string_free(&symname);
@ -2312,6 +2420,7 @@ static void v9fs_flush(void *opaque)
V9fsState *s = pdu->s;
pdu_unmarshal(pdu, offset, "w", &tag);
trace_v9fs_flush(pdu->tag, pdu->id, tag);
QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
if (cancel_pdu->tag == tag) {
@ -2342,6 +2451,7 @@ static void v9fs_link(void *opaque)
int err = 0;
pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data);
dfidp = get_fid(pdu, dfid);
if (dfidp == NULL) {
@ -2375,6 +2485,7 @@ static void v9fs_remove(void *opaque)
V9fsPDU *pdu = opaque;
pdu_unmarshal(pdu, offset, "d", &fid);
trace_v9fs_remove(pdu->tag, pdu->id, fid);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
@ -2382,7 +2493,7 @@ static void v9fs_remove(void *opaque)
goto out_nofid;
}
/* if fs driver is not path based, return EOPNOTSUPP */
if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) {
if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
err = -EOPNOTSUPP;
goto out_err;
}
@ -2417,6 +2528,7 @@ static void v9fs_unlinkat(void *opaque)
V9fsPDU *pdu = opaque;
pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
flags = dotl_to_at_flags(flags);
dfidp = get_fid(pdu, dfid);
if (dfidp == NULL) {
@ -2528,7 +2640,7 @@ static void v9fs_rename(void *opaque)
}
BUG_ON(fidp->fid_type != P9_FID_NONE);
/* if fs driver is not path based, return EOPNOTSUPP */
if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) {
if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
err = -EOPNOTSUPP;
goto out;
}
@ -2601,7 +2713,7 @@ static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
if (err < 0) {
goto out;
}
if (s->ctx.flags & PATHNAME_FSCONTEXT) {
if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
/* Only for path based fid we need to do the below fixup */
v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
&newdirfidp->path, new_name);
@ -2653,6 +2765,8 @@ static void v9fs_wstat(void *opaque)
V9fsState *s = pdu->s;
pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
trace_v9fs_wstat(pdu->tag, pdu->id, fid,
v9stat.mode, v9stat.atime, v9stat.mtime);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
@ -2821,6 +2935,7 @@ static void v9fs_mknod(void *opaque)
pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
&major, &minor, &gid);
trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
@ -2838,6 +2953,7 @@ static void v9fs_mknod(void *opaque)
out:
put_fid(pdu, fidp);
out_nofid:
trace_v9fs_mknod_return(pdu->tag, pdu->id, qid.type, qid.version, qid.path);
complete_pdu(s, pdu, err);
v9fs_string_free(&name);
}
@ -2865,6 +2981,10 @@ static void v9fs_lock(void *opaque)
pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type,
&flock->flags, &flock->start, &flock->length,
&flock->proc_id, &flock->client_id);
trace_v9fs_lock(pdu->tag, pdu->id, fid,
flock->type, flock->start, flock->length);
status = P9_LOCK_ERROR;
/* We support only block flag now (that too ignored currently) */
@ -2887,6 +3007,7 @@ out:
out_nofid:
err = offset;
err += pdu_marshal(pdu, offset, "b", status);
trace_v9fs_lock_return(pdu->tag, pdu->id, status);
complete_pdu(s, pdu, err);
v9fs_string_free(&flock->client_id);
g_free(flock);
@ -2911,6 +3032,9 @@ static void v9fs_getlock(void *opaque)
&glock->start, &glock->length, &glock->proc_id,
&glock->client_id);
trace_v9fs_getlock(pdu->tag, pdu->id, fid,
glock->type, glock->start, glock->length);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
@ -2920,7 +3044,7 @@ static void v9fs_getlock(void *opaque)
if (err < 0) {
goto out;
}
glock->type = F_UNLCK;
glock->type = P9_LOCK_TYPE_UNLCK;
offset += pdu_marshal(pdu, offset, "bqqds", glock->type,
glock->start, glock->length, glock->proc_id,
&glock->client_id);
@ -2928,6 +3052,9 @@ static void v9fs_getlock(void *opaque)
out:
put_fid(pdu, fidp);
out_nofid:
trace_v9fs_getlock_return(pdu->tag, pdu->id, glock->type, glock->start,
glock->length, glock->proc_id);
complete_pdu(s, pdu, err);
v9fs_string_free(&glock->client_id);
g_free(glock);
@ -2948,6 +3075,8 @@ static void v9fs_mkdir(void *opaque)
pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
@ -2963,6 +3092,8 @@ static void v9fs_mkdir(void *opaque)
out:
put_fid(pdu, fidp);
out_nofid:
trace_v9fs_mkdir_return(pdu->tag, pdu->id,
qid.type, qid.version, qid.path, err);
complete_pdu(pdu->s, pdu, err);
v9fs_string_free(&name);
}
@ -2980,6 +3111,8 @@ static void v9fs_xattrwalk(void *opaque)
V9fsState *s = pdu->s;
pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data);
file_fidp = get_fid(pdu, fid);
if (file_fidp == NULL) {
err = -ENOENT;
@ -3056,6 +3189,7 @@ out:
put_fid(pdu, xattr_fidp);
}
out_nofid:
trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
complete_pdu(s, pdu, err);
v9fs_string_free(&name);
}
@ -3075,6 +3209,7 @@ static void v9fs_xattrcreate(void *opaque)
pdu_unmarshal(pdu, offset, "dsqd",
&fid, &name, &size, &flags);
trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
file_fidp = get_fid(pdu, fid);
if (file_fidp == NULL) {
@ -3111,6 +3246,7 @@ static void v9fs_readlink(void *opaque)
V9fsFidState *fidp;
pdu_unmarshal(pdu, offset, "d", &fid);
trace_v9fs_readlink(pdu->tag, pdu->id, fid);
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
@ -3128,6 +3264,7 @@ static void v9fs_readlink(void *opaque)
out:
put_fid(pdu, fidp);
out_nofid:
trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
complete_pdu(pdu->s, pdu, err);
}
@ -3179,9 +3316,6 @@ static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
Coroutine *co;
CoroutineEntry *handler;
if (debug_9p_pdu) {
pprint_pdu(pdu);
}
if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
(pdu_co_handlers[pdu->id] == NULL)) {
handler = v9fs_op_not_supp;

View file

@ -352,6 +352,35 @@ typedef struct V9fsMkState {
V9fsString fullname;
} V9fsMkState;
/* 9p2000.L open flags */
#define P9_DOTL_RDONLY 00000000
#define P9_DOTL_WRONLY 00000001
#define P9_DOTL_RDWR 00000002
#define P9_DOTL_NOACCESS 00000003
#define P9_DOTL_CREATE 00000100
#define P9_DOTL_EXCL 00000200
#define P9_DOTL_NOCTTY 00000400
#define P9_DOTL_TRUNC 00001000
#define P9_DOTL_APPEND 00002000
#define P9_DOTL_NONBLOCK 00004000
#define P9_DOTL_DSYNC 00010000
#define P9_DOTL_FASYNC 00020000
#define P9_DOTL_DIRECT 00040000
#define P9_DOTL_LARGEFILE 00100000
#define P9_DOTL_DIRECTORY 00200000
#define P9_DOTL_NOFOLLOW 00400000
#define P9_DOTL_NOATIME 01000000
#define P9_DOTL_CLOEXEC 02000000
#define P9_DOTL_SYNC 04000000
/* 9p2000.L at flags */
#define P9_DOTL_AT_REMOVEDIR 0x200
/* 9P2000.L lock type */
#define P9_LOCK_TYPE_RDLCK 0
#define P9_LOCK_TYPE_WRLCK 1
#define P9_LOCK_TYPE_UNLCK 2
#define P9_LOCK_SUCCESS 0
#define P9_LOCK_BLOCKED 1
#define P9_LOCK_ERROR 2
@ -393,21 +422,21 @@ static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
static inline void v9fs_path_write_lock(V9fsState *s)
{
if (s->ctx.flags & PATHNAME_FSCONTEXT) {
if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
qemu_co_rwlock_wrlock(&s->rename_lock);
}
}
static inline void v9fs_path_read_lock(V9fsState *s)
{
if (s->ctx.flags & PATHNAME_FSCONTEXT) {
if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
qemu_co_rwlock_rdlock(&s->rename_lock);
}
}
static inline void v9fs_path_unlock(V9fsState *s)
{
if (s->ctx.flags & PATHNAME_FSCONTEXT) {
if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
qemu_co_rwlock_unlock(&s->rename_lock);
}
}

View file

@ -83,11 +83,6 @@
/* Flags track per-device state like workarounds for quirks in older guests. */
#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG (1 << 0)
/* Performance improves when virtqueue kick processing is decoupled from the
* vcpu thread using ioeventfd for some devices. */
#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
#define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
/* QEMU doesn't strictly need write barriers since everything runs in
* lock-step. We'll leave the calls to wmb() in though to make it obvious for
* KVM or if kqemu gets SMP support.

View file

@ -18,6 +18,11 @@
#include "virtio-net.h"
#include "virtio-serial.h"
/* Performance improves when virtqueue kick processing is decoupled from the
* vcpu thread using ioeventfd for some devices. */
#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
#define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
typedef struct {
PCIDevice pci_dev;
VirtIODevice *vdev;

View file

@ -165,11 +165,11 @@ static QemuOptsList qemu_chardev_opts = {
QemuOptsList qemu_fsdev_opts = {
.name = "fsdev",
.implied_opt_name = "fstype",
.implied_opt_name = "fsdriver",
.head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
.desc = {
{
.name = "fstype",
.name = "fsdriver",
.type = QEMU_OPT_STRING,
}, {
.name = "path",
@ -177,6 +177,9 @@ QemuOptsList qemu_fsdev_opts = {
}, {
.name = "security_model",
.type = QEMU_OPT_STRING,
}, {
.name = "writeout",
.type = QEMU_OPT_STRING,
},
{ /*End of list */ }
},
@ -184,11 +187,11 @@ QemuOptsList qemu_fsdev_opts = {
QemuOptsList qemu_virtfs_opts = {
.name = "virtfs",
.implied_opt_name = "fstype",
.implied_opt_name = "fsdriver",
.head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
.desc = {
{
.name = "fstype",
.name = "fsdriver",
.type = QEMU_OPT_STRING,
}, {
.name = "path",
@ -199,6 +202,9 @@ QemuOptsList qemu_virtfs_opts = {
}, {
.name = "security_model",
.type = QEMU_OPT_STRING,
}, {
.name = "writeout",
.type = QEMU_OPT_STRING,
},
{ /*End of list */ }

View file

@ -522,73 +522,103 @@ possible drivers and properties, use @code{-device ?} and
@code{-device @var{driver},?}.
ETEXI
DEFHEADING()
DEFHEADING(File system options:)
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
"-fsdev local,id=id,path=path,security_model=[mapped|passthrough|none]\n",
"-fsdev fsdriver,id=id,path=path,[security_model={mapped|passthrough|none}]\n"
" [,writeout=immediate]\n",
QEMU_ARCH_ALL)
STEXI
The general form of a File system device option is:
@table @option
@item -fsdev @var{fstype} ,id=@var{id} [,@var{options}]
@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}]
@findex -fsdev
Fstype is one of:
@option{local},
The specific Fstype will determine the applicable options.
Options to each backend are described below.
@item -fsdev local ,id=@var{id} ,path=@var{path} ,security_model=@var{security_model}
Create a file-system-"device" for local-filesystem.
@option{local} is only available on Linux.
@option{path} specifies the path to be exported. @option{path} is required.
@option{security_model} specifies the security model to be followed.
@option{security_model} is required.
Define a new file system device. Valid options are:
@table @option
@item @var{fsdriver}
This option specifies the fs driver backend to use.
Currently "local" and "handle" file system drivers are supported.
@item id=@var{id}
Specifies identifier for this device
@item path=@var{path}
Specifies the export path for the file system device. Files under
this path will be available to the 9p client on the guest.
@item security_model=@var{security_model}
Specifies the security model to be used for this export path.
Supported security models are "passthrough", "mapped" and "none".
In "passthrough" security model, files are stored using the same
credentials as they are created on the guest. This requires qemu
to run as root. In "mapped" security model, some of the file
attributes like uid, gid, mode bits and link target are stored as
file attributes. Directories exported by this security model cannot
interact with other unix tools. "none" security model is same as
passthrough except the sever won't report failures if it fails to
set file attributes like ownership. Security model is mandatory
only for local fsdriver. Other fsdrivers (like handle) don't take
security model as a parameter.
@item writeout=@var{writeout}
This is an optional argument. The only supported value is "immediate".
This means that host page cache will be used to read and write data but
write notification will be sent to the guest only when the data has been
reported as written by the storage subsystem.
@end table
-fsdev option is used along with -device driver "virtio-9p-pci".
@item -device virtio-9p-pci,fsdev=@var{id},mount_tag=@var{mount_tag}
Options for virtio-9p-pci driver are:
@table @option
@item fsdev=@var{id}
Specifies the id value specified along with -fsdev option
@item mount_tag=@var{mount_tag}
Specifies the tag name to be used by the guest to mount this export point
@end table
ETEXI
DEFHEADING()
DEFHEADING(Virtual File system pass-through options:)
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]\n",
QEMU_ARCH_ALL)
STEXI
The general form of a Virtual File system pass-through option is:
@table @option
@item -virtfs @var{fstype} [,@var{options}]
@item -virtfs @var{fsdriver},path=@var{path},mount_tag=@var{mount_tag},security_model=@var{security_model}[,writeout=@var{writeout}]
@findex -virtfs
Fstype is one of:
@option{local},
The specific Fstype will determine the applicable options.
Options to each backend are described below.
@item -virtfs local ,path=@var{path} ,mount_tag=@var{mount_tag} ,security_model=@var{security_model}
Create a Virtual file-system-pass through for local-filesystem.
@option{local} is only available on Linux.
@option{path} specifies the path to be exported. @option{path} is required.
@option{security_model} specifies the security model to be followed.
@option{security_model} is required.
@option{mount_tag} specifies the tag with which the exported file is mounted.
@option{mount_tag} is required.
The general form of a Virtual File system pass-through options are:
@table @option
@item @var{fsdriver}
This option specifies the fs driver backend to use.
Currently "local" and "handle" file system drivers are supported.
@item id=@var{id}
Specifies identifier for this device
@item path=@var{path}
Specifies the export path for the file system device. Files under
this path will be available to the 9p client on the guest.
@item security_model=@var{security_model}
Specifies the security model to be used for this export path.
Supported security models are "passthrough", "mapped" and "none".
In "passthrough" security model, files are stored using the same
credentials as they are created on the guest. This requires qemu
to run as root. In "mapped" security model, some of the file
attributes like uid, gid, mode bits and link target are stored as
file attributes. Directories exported by this security model cannot
interact with other unix tools. "none" security model is same as
passthrough except the sever won't report failures if it fails to
set file attributes like ownership. Security model is mandatory only
for local fsdriver. Other fsdrivers (like handle) don't take security
model as a parameter.
@item writeout=@var{writeout}
This is an optional argument. The only supported value is "immediate".
This means that host page cache will be used to read and write data but
write notification will be sent to the guest only when the data has been
reported as written by the storage subsystem.
@end table
ETEXI

142
scripts/analyse-9p-simpletrace.py Executable file
View file

@ -0,0 +1,142 @@
#!/usr/bin/env python
# Pretty print 9p simpletrace log
# Usage: ./analyse-9p-simpletrace <trace-events> <trace-pid>
#
# Author: Harsh Prateek Bora
import simpletrace
class VirtFSRequestTracker(simpletrace.Analyzer):
def begin(self):
print "Pretty printing 9p simpletrace log ..."
def complete_pdu(self, tag, id, err):
print "ERROR (tag =", tag, ", id =", id, ",err =", err, ")"
def v9fs_version(self, tag, id, msize, version):
print "TVERSION (tag =", tag, ", msize =", msize, ", version =", version, ")"
def v9fs_version_return(self, tag, id, msize, version):
print "RVERSION (tag =", tag, ", msize =", msize, ", version =", version, ")"
def v9fs_attach(self, tag, id, fid, afid, uname, aname):
print "TATTACH (tag =", tag, ", fid =", fid, ", afid =", afid, ", uname =", uname, ", aname =", aname, ")"
def v9fs_attach_return(self, tag, id, type, verison, path):
print "RATTACH (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "})"
def v9fs_stat(self, tag, id, fid):
print "TSTAT (tag =", tag, ", fid =", fid, ")"
def v9fs_stat_return(self, tag, id, mode, atime, mtime, length):
print "RSTAT (tag =", tag, ", mode =", mode, ", atime =", atime, ", mtime =", mtime, ", length =", length, ")"
def v9fs_getattr(self, tag, id, fid, request_mask):
print "TGETATTR (tag =", tag, ", fid =", fid, ", request_mask =", hex(request_mask), ")"
def v9fs_getattr_return(self, tag, id, result_mask, mode, uid, gid):
print "RGETATTR (tag =", tag, ", result_mask =", hex(result_mask), ", mode =", oct(mode), ", uid =", uid, ", gid =", gid, ")"
def v9fs_walk(self, tag, id, fid, newfid, nwnames):
print "TWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", nwnames =", nwnames, ")"
def v9fs_walk_return(self, tag, id, nwnames, qids):
print "RWALK (tag =", tag, ", nwnames =", nwnames, ", qids =", hex(qids), ")"
def v9fs_open(self, tag, id, fid, mode):
print "TOPEN (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ")"
def v9fs_open_return(self, tag, id, type, version, path, iounit):
print "ROPEN (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
def v9fs_lcreate(self, tag, id, dfid, flags, mode, gid):
print "TLCREATE (tag =", tag, ", dfid =", dfid, ", flags =", oct(flags), ", mode =", oct(mode), ", gid =", gid, ")"
def v9fs_lcreate_return(self, id, type, version, path, iounit):
print "RLCREATE (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
def v9fs_fsync(self, tag, id, fid, datasync):
print "TFSYNC (tag =", tag, ", fid =", fid, ", datasync =", datasync, ")"
def v9fs_clunk(self, tag, id, fid):
print "TCLUNK (tag =", tag, ", fid =", fid, ")"
def v9fs_read(self, tag, id, fid, off, max_count):
print "TREAD (tag =", tag, ", fid =", fid, ", off =", off, ", max_count =", max_count, ")"
def v9fs_read_return(self, tag, id, count, err):
print "RREAD (tag =", tag, ", count =", count, ", err =", err, ")"
def v9fs_readdir(self, tag, id, fid, offset, max_count):
print "TREADDIR (tag =", tag, ", fid =", fid, ", offset =", offset, ", max_count =", max_count, ")"
def v9fs_readdir_return(self, tag, id, count, retval):
print "RREADDIR (tag =", tag, ", count =", count, ", retval =", retval, ")"
def v9fs_write(self, tag, id, fid, off, count, cnt):
print "TWRITE (tag =", tag, ", fid =", fid, ", off =", off, ", count =", count, ", cnt =", cnt, ")"
def v9fs_write_return(self, tag, id, total, err):
print "RWRITE (tag =", tag, ", total =", total, ", err =", err, ")"
def v9fs_create(self, tag, id, fid, perm, name, mode):
print "TCREATE (tag =", tag, ", fid =", fid, ", perm =", oct(perm), ", name =", name, ", mode =", oct(mode), ")"
def v9fs_create_return(self, tag, id, type, verison, path, iounit):
print "RCREATE (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
def v9fs_symlink(self, tag, id, fid, name, symname, gid):
print "TSYMLINK (tag =", tag, ", fid =", fid, ", name =", name, ", symname =", symname, ", gid =", gid, ")"
def v9fs_symlink_return(self, tag, id, type, version, path):
print "RSYMLINK (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "})"
def v9fs_flush(self, tag, id, flush_tag):
print "TFLUSH (tag =", tag, ", flush_tag =", flush_tag, ")"
def v9fs_link(self, tag, id, dfid, oldfid, name):
print "TLINK (tag =", tag, ", dfid =", dfid, ", oldfid =", oldfid, ", name =", name, ")"
def v9fs_remove(self, tag, id, fid):
print "TREMOVE (tag =", tag, ", fid =", fid, ")"
def v9fs_wstat(self, tag, id, fid, mode, atime, mtime):
print "TWSTAT (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", atime =", atime, "mtime =", mtime, ")"
def v9fs_mknod(self, tag, id, fid, mode, major, minor):
print "TMKNOD (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", major =", major, ", minor =", minor, ")"
def v9fs_lock(self, tag, id, fid, type, start, length):
print "TLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
def v9fs_lock_return(self, tag, id, status):
print "RLOCK (tag =", tag, ", status =", status, ")"
def v9fs_getlock(self, tag, id, fid, type, start, length):
print "TGETLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
def v9fs_getlock_return(self, tag, id, type, start, length, proc_id):
print "RGETLOCK (tag =", tag, "type =", type, ", start =", start, ", length =", length, ", proc_id =", proc_id, ")"
def v9fs_mkdir(self, tag, id, fid, name, mode, gid):
print "TMKDIR (tag =", tag, ", fid =", fid, ", name =", name, ", mode =", mode, ", gid =", gid, ")"
def v9fs_mkdir_return(self, tag, id, type, version, path, err):
print "RMKDIR (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "}, err =", err, ")"
def v9fs_xattrwalk(self, tag, id, fid, newfid, name):
print "TXATTRWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", xattr name =", name, ")"
def v9fs_xattrwalk_return(self, tag, id, size):
print "RXATTRWALK (tag =", tag, ", xattrsize =", size, ")"
def v9fs_xattrcreate(self, tag, id, fid, name, size, flags):
print "TXATTRCREATE (tag =", tag, ", fid =", fid, ", name =", name, ", xattrsize =", size, ", flags =", flags, ")"
def v9fs_readlink(self, tag, id, fid):
print "TREADLINK (tag =", tag, ", fid =", fid, ")"
def v9fs_readlink_return(self, tag, id, target):
print "RREADLINK (tag =", tag, ", target =", target, ")"
simpletrace.run(VirtFSRequestTracker())

View file

@ -552,3 +552,49 @@ open_eth_reg_read(uint32_t addr, uint32_t v) "MAC[%02x] -> %08x"
open_eth_reg_write(uint32_t addr, uint32_t v) "MAC[%02x] <- %08x"
open_eth_desc_read(uint32_t addr, uint32_t v) "DESC[%04x] -> %08x"
open_eth_desc_write(uint32_t addr, uint32_t v) "DESC[%04x] <- %08x"
# hw/9pfs/virtio-9p.c
complete_pdu(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 %d id %d fid %d afid %d 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_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""
v9fs_getattr_return(uint16_t tag, uint8_t id, uint64_t result_mask, uint32_t mode, uint32_t uid, uint32_t gid) "tag %d id %d getattr={result_mask %"PRId64" mode %u uid %u gid %u}"
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_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_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, int64_t off, int32_t max_count) "tag %d id %d fid %d off %"PRId64" max_count %d"
v9fs_read_return(uint16_t tag, uint8_t id, int32_t count, ssize_t err) "tag %d id %d count %d err %zd"
v9fs_readdir(uint16_t tag, uint8_t id, int32_t fid, int64_t offset, int32_t max_count) "tag %d id %d fid %d offset %"PRId64" max_count %d"
v9fs_readdir_return(uint16_t tag, uint8_t id, int32_t count, ssize_t retval) "tag %d id %d count %d retval %zd"
v9fs_write(uint16_t tag, uint8_t id, int32_t fid, int64_t off, int32_t count, int cnt) "tag %d id %d fid %d off %"PRId64" count %d 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_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_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 %d id %d fid %d stat={mode %d atime %d mtime}"
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_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 %d id %d fid %d name %s mode %d"
v9fs_mkdir_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int err) "tag %d id %d qid={type %d version %d path %"PRId64"}"
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, int64_t size, int flags) "tag %d id %d fid %d name %s size %"PRId64" flags %d"
v9fs_readlink(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
v9fs_readlink_return(uint16_t tag, uint8_t id, char* target) "tag %d id %d name %s"

24
vl.c
View file

@ -2783,6 +2783,7 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_virtfs: {
QemuOpts *fsdev;
QemuOpts *device;
const char *writeout;
olist = qemu_find_opts("virtfs");
if (!olist) {
@ -2795,16 +2796,14 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
if (qemu_opt_get(opts, "fstype") == NULL ||
if (qemu_opt_get(opts, "fsdriver") == NULL ||
qemu_opt_get(opts, "mount_tag") == NULL ||
qemu_opt_get(opts, "path") == NULL ||
qemu_opt_get(opts, "security_model") == NULL) {
fprintf(stderr, "Usage: -virtfs fstype,path=/share_path/,"
"security_model=[mapped|passthrough|none],"
qemu_opt_get(opts, "path") == NULL) {
fprintf(stderr, "Usage: -virtfs fsdriver,path=/share_path/,"
"[security_model={mapped|passthrough|none}],"
"mount_tag=tag.\n");
exit(1);
}
fsdev = qemu_opts_create(qemu_find_opts("fsdev"),
qemu_opt_get(opts, "mount_tag"), 1);
if (!fsdev) {
@ -2812,7 +2811,18 @@ int main(int argc, char **argv, char **envp)
qemu_opt_get(opts, "mount_tag"));
exit(1);
}
qemu_opt_set(fsdev, "fstype", qemu_opt_get(opts, "fstype"));
writeout = qemu_opt_get(opts, "writeout");
if (writeout) {
#ifdef CONFIG_SYNC_FILE_RANGE
qemu_opt_set(fsdev, "writeout", writeout);
#else
fprintf(stderr, "writeout=immediate not supported on "
"this platform\n");
exit(1);
#endif
}
qemu_opt_set(fsdev, "fsdriver", qemu_opt_get(opts, "fsdriver"));
qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path"));
qemu_opt_set(fsdev, "security_model",
qemu_opt_get(opts, "security_model"));