aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.objs2
-rwxr-xr-xconfigure33
-rw-r--r--fsdev/file-op-9p.h51
-rw-r--r--fsdev/qemu-fsdev.c69
-rw-r--r--fsdev/qemu-fsdev.h20
-rw-r--r--hw/9pfs/cofile.c24
-rw-r--r--hw/9pfs/cofs.c2
-rw-r--r--hw/9pfs/virtio-9p-coth.h3
-rw-r--r--hw/9pfs/virtio-9p-debug.c646
-rw-r--r--hw/9pfs/virtio-9p-debug.h6
-rw-r--r--hw/9pfs/virtio-9p-device.c70
-rw-r--r--hw/9pfs/virtio-9p-handle.c120
-rw-r--r--hw/9pfs/virtio-9p-local.c126
-rw-r--r--hw/9pfs/virtio-9p.c170
-rw-r--r--hw/9pfs/virtio-9p.h35
-rw-r--r--hw/virtio-pci.c5
-rw-r--r--hw/virtio-pci.h5
-rw-r--r--qemu-config.c14
-rw-r--r--qemu-options.hx122
-rwxr-xr-xscripts/analyse-9p-simpletrace.py142
-rw-r--r--trace-events46
-rw-r--r--vl.c24
22 files changed, 852 insertions, 883 deletions
diff --git a/Makefile.objs b/Makefile.objs
index 44d9bb9043..9e2077833e 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -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
diff --git a/configure b/configure
index 9b4fe34fce..4f87e0a43b 100755
--- a/configure
+++ b/configure
@@ -2557,6 +2557,31 @@ EOF
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)
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 8de8abfd5b..908e2a5edc 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -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;
diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
index 768819f575..5977bcca4c 100644
--- a/fsdev/qemu-fsdev.c
+++ b/fsdev/qemu-fsdev.c
@@ -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 (!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 (!sec_model) {
- fprintf(stderr, "fsdev: No security_model specified.\n");
+ 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);
- return 0;
+ 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;
}
diff --git a/fsdev/qemu-fsdev.h b/fsdev/qemu-fsdev.h
index e04931a58d..5099085720 100644
--- a/fsdev/qemu-fsdev.h
+++ b/fsdev/qemu-fsdev.h
@@ -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
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 7ad4bec005..692811e5ab 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -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;
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 68745add1e..83f125bd47 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -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;
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index 4630080e53..ca96b9cf2f 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -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
diff --git a/hw/9pfs/virtio-9p-debug.c b/hw/9pfs/virtio-9p-debug.c
deleted file mode 100644
index 96925f04a4..0000000000
--- a/hw/9pfs/virtio-9p-debug.c
+++ /dev/null
@@ -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);
-}
diff --git a/hw/9pfs/virtio-9p-debug.h b/hw/9pfs/virtio-9p-debug.h
deleted file mode 100644
index d9a249118d..0000000000
--- a/hw/9pfs/virtio-9p-debug.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _QEMU_VIRTIO_9P_DEBUG_H
-#define _QEMU_VIRTIO_9P_DEBUG_H
-
-void pprint_pdu(V9fsPDU *pdu);
-
-#endif
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 513e181c82..bba4c54762 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -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.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 (!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;
+ } else if (fse->export_flags & V9FS_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;
+ } else if (fse->export_flags & V9FS_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.fs_root = g_strdup(fse->path);
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),
diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c
index 5c8b5ed471..98809f1642 100644
--- a/hw/9pfs/virtio-9p-handle.c
+++ b/hw/9pfs/virtio-9p-handle.c
@@ -21,49 +21,56 @@
#include <sys/un.h>
#include <attr/xattr.h>
#include <unistd.h>
-
-struct handle_data {
- int mountfd;
- int handle_bytes;
-};
-
-#if __GLIBC__ <= 2 && __GLIBC_MINOR__ < 14
-struct file_handle {
- unsigned int handle_bytes;
- int handle_type;
- unsigned char handle[0];
-};
+#include <linux/fs.h>
+#ifdef CONFIG_LINUX_MAGIC_H
+#include <linux/magic.h>
#endif
+#include <sys/ioctl.h>
-#ifndef AT_EMPTY_PATH
-#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
+#ifndef XFS_SUPER_MAGIC
+#define XFS_SUPER_MAGIC 0x58465342
#endif
-#ifndef O_PATH
-#define O_PATH 010000000
+#ifndef EXT2_SUPER_MAGIC
+#define EXT2_SUPER_MAGIC 0xEF53
#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
+#ifndef REISERFS_SUPER_MAGIC
+#define REISERFS_SUPER_MAGIC 0x52654973
#endif
+#ifndef BTRFS_SUPER_MAGIC
+#define BTRFS_SUPER_MAGIC 0x9123683E
#endif
-#ifdef __NR_name_to_handle_at
+struct handle_data {
+ int mountfd;
+ int handle_bytes;
+};
+
+#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 syscall(__NR_name_to_handle_at, dirfd, name, fh, mnt_id, 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 syscall(__NR_open_by_handle_at, mountfd, fh, 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];
+};
+
+#ifndef AT_EMPTY_PATH
+#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
+#endif
+#ifndef O_PATH
+#define O_PATH 010000000
+#endif
+
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) {
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 9559ff6550..d561de88f0 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -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 = {
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index c01c31aa25..aab3bebcc7 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -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;
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 60b8a56e57..802f5809d1 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -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);
}
}
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index df27c198b0..ca5923c495 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -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.
diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h
index 14c10f7d67..f8404de92b 100644
--- a/hw/virtio-pci.h
+++ b/hw/virtio-pci.h
@@ -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;
diff --git a/qemu-config.c b/qemu-config.c
index 7a7854fd06..90b6b3e85b 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -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 */ }
diff --git a/qemu-options.hx b/qemu-options.hx
index d4fe990e27..5d2a7765e8 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -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
diff --git a/scripts/analyse-9p-simpletrace.py b/scripts/analyse-9p-simpletrace.py
new file mode 100755
index 0000000000..4358d6b594
--- /dev/null
+++ b/scripts/analyse-9p-simpletrace.py
@@ -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())
diff --git a/trace-events b/trace-events
index a06c6c5282..fc13733250 100644
--- a/trace-events
+++ b/trace-events
@@ -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"
diff --git a/vl.c b/vl.c
index fff2b4c80f..66f70fb6ae 100644
--- a/vl.c
+++ b/vl.c
@@ -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"));