瀏覽代碼

Merge tag 'pull-9p-20250207' of https://github.com/cschoenebeck/qemu into staging

9pfs changes:

* Greg Kurz steps back as maintainer of 9pfs.

* Make multidevs=remap default option (instead of multidevs=warn)
  and update documentation related to this option.

* Improve tracing (i.e. usefulness of log output content).

# -----BEGIN PGP SIGNATURE-----
#
# iQJLBAABCgA1FiEEltjREM96+AhPiFkBNMK1h2Wkc5UFAmel2AEXHHFlbXVfb3Nz
# QGNydWRlYnl0ZS5jb20ACgkQNMK1h2Wkc5UOuw//YMqU1N1JV7ppHMOKgu9GBSPI
# xFS5fhGHQd0b2DhXlX0m0vlwCN5m7up7Q1NwkgXzfaIV3wdU8XH1DgMXonjQdBaT
# ipIGdCR9aeGCUlFjlkQCEUVooDAuyU2zqIpfzvX7eCUFI96S2DI+jjmSqOhlJSsz
# yJnTJOK0LuoMpaFDxHJiEuTfoMycUWT78hTHRE8h/UWfTcKrzz5uIajq05bA1QLd
# XRtMa2k8ZWZf+uOcky3Qq/g5UHCc9LUidnVvTBejRQeEeE+qhLX9CzTUF+elNRiF
# BKPjQLfdyTMeleOj3KWxAkIV0GP4LA5naEi7Li56Kx/qOSySOnlbfUR0rXm1L58t
# yJdtavJEXFiRDa1BPvZeuDEGbSf229gOvQtD9yhURtw9XtdhZ8WuX7edes9/S5xz
# nc0slBD4UMkUL0VqD5LX4nwW/IJbUGD/sgqg1sMMXC+cSptPWCTQjf56VGZHg0Kf
# oasIe2pKyOu0NEIpxpolu+AGlgGsOHgEknBdG5GJ/dFzKb+9sukVEFxzZP/eRQjp
# d7ShWkn1o96vMgReFaYIXboVXNdeePDjfvLLD8+xKp3KEvidGEQs1PGPWyU0juIT
# 2en3PwZfYvm3Wfys3dAl7g1XJOzFM177SHKYKbEEeziIeRNN5oTjPxAIu0+M2yVK
# y2Khd01ZJQBGhiYYgVw=
# =Tr40
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 07 Feb 2025 04:53:05 EST
# gpg:                using RSA key 96D8D110CF7AF8084F88590134C2B58765A47395
# gpg:                issuer "qemu_oss@crudebyte.com"
# gpg: Good signature from "Christian Schoenebeck <qemu_oss@crudebyte.com>" [unknown]
# gpg: WARNING: The key's User ID is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: ECAB 1A45 4014 1413 BA38  4926 30DB 47C3 A012 D5F4
#      Subkey fingerprint: 96D8 D110 CF7A F808 4F88  5901 34C2 B587 65A4 7395

* tag 'pull-9p-20250207' of https://github.com/cschoenebeck/qemu:
  MAINTAINERS: Mark me as reviewer only for 9pfs
  9pfs: improve v9fs_open() tracing
  9pfs: make multidevs=remap default
  9pfs: improve v9fs_walk() tracing

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Stefan Hajnoczi 6 月之前
父節點
當前提交
0a841b0b64
共有 8 個文件被更改,包括 129 次插入32 次删除
  1. 1 2
      MAINTAINERS
  2. 3 0
      hw/9pfs/9p-local.c
  3. 50 0
      hw/9pfs/9p-util-generic.c
  4. 6 0
      hw/9pfs/9p-util.h
  5. 39 6
      hw/9pfs/9p.c
  6. 1 0
      hw/9pfs/meson.build
  7. 2 2
      hw/9pfs/trace-events
  8. 27 22
      qemu-options.hx

+ 1 - 2
MAINTAINERS

@@ -2254,8 +2254,8 @@ F: include/system/balloon.h
 F: tests/qtest/virtio-balloon-test.c
 F: tests/qtest/virtio-balloon-test.c
 
 
 virtio-9p
 virtio-9p
-M: Greg Kurz <groug@kaod.org>
 M: Christian Schoenebeck <qemu_oss@crudebyte.com>
 M: Christian Schoenebeck <qemu_oss@crudebyte.com>
+R: Greg Kurz <groug@kaod.org>
 S: Maintained
 S: Maintained
 W: https://wiki.qemu.org/Documentation/9p
 W: https://wiki.qemu.org/Documentation/9p
 F: hw/9pfs/
 F: hw/9pfs/
@@ -2263,7 +2263,6 @@ X: hw/9pfs/xen-9p*
 F: fsdev/
 F: fsdev/
 F: tests/qtest/virtio-9p-test.c
 F: tests/qtest/virtio-9p-test.c
 F: tests/qtest/libqos/virtio-9p*
 F: tests/qtest/libqos/virtio-9p*
-T: git https://gitlab.com/gkurz/qemu.git 9p-next
 T: git https://github.com/cschoenebeck/qemu.git 9p.next
 T: git https://github.com/cschoenebeck/qemu.git 9p.next
 
 
 virtio-blk
 virtio-blk

+ 3 - 0
hw/9pfs/9p-local.c

@@ -1538,6 +1538,9 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
                               "[remap|forbid|warn]\n");
                               "[remap|forbid|warn]\n");
             return -1;
             return -1;
         }
         }
+    } else {
+        fse->export_flags &= ~V9FS_FORBID_MULTIDEVS;
+        fse->export_flags |= V9FS_REMAP_INODES;
     }
     }
 
 
     if (!path) {
     if (!path) {

+ 50 - 0
hw/9pfs/9p-util-generic.c

@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "9p-util.h"
+#include <glib/gstrfuncs.h>
+
+char *qemu_open_flags_tostr(int flags)
+{
+    int acc = flags & O_ACCMODE;
+    return g_strconcat(
+        (acc == O_WRONLY) ? "WRONLY" : (acc == O_RDONLY) ? "RDONLY" : "RDWR",
+        (flags & O_CREAT) ? "|CREAT" : "",
+        (flags & O_EXCL) ? "|EXCL" : "",
+        (flags & O_NOCTTY) ? "|NOCTTY" : "",
+        (flags & O_TRUNC) ? "|TRUNC" : "",
+        (flags & O_APPEND) ? "|APPEND" : "",
+        (flags & O_NONBLOCK) ? "|NONBLOCK" : "",
+        (flags & O_DSYNC) ? "|DSYNC" : "",
+        #ifdef O_DIRECT
+        (flags & O_DIRECT) ? "|DIRECT" : "",
+        #endif
+        (flags & O_LARGEFILE) ? "|LARGEFILE" : "",
+        (flags & O_DIRECTORY) ? "|DIRECTORY" : "",
+        (flags & O_NOFOLLOW) ? "|NOFOLLOW" : "",
+        #ifdef O_NOATIME
+        (flags & O_NOATIME) ? "|NOATIME" : "",
+        #endif
+        #ifdef O_CLOEXEC
+        (flags & O_CLOEXEC) ? "|CLOEXEC" : "",
+        #endif
+        #ifdef __O_SYNC
+        (flags & __O_SYNC) ? "|SYNC" : "",
+        #else
+        ((flags & O_SYNC) == O_SYNC) ? "|SYNC" : "",
+        #endif
+        #ifdef O_PATH
+        (flags & O_PATH) ? "|PATH" : "",
+        #endif
+        #ifdef __O_TMPFILE
+        (flags & __O_TMPFILE) ? "|TMPFILE" : "",
+        #elif defined(O_TMPFILE)
+        ((flags & O_TMPFILE) == O_TMPFILE) ? "|TMPFILE" : "",
+        #endif
+        /* O_NDELAY is usually just an alias of O_NONBLOCK */
+        #if defined(O_NDELAY) && O_NDELAY != O_NONBLOCK
+        (flags & O_NDELAY) ? "|NDELAY" : "",
+        #endif
+        NULL /* always last (required NULL termination) */
+    );
+}

+ 6 - 0
hw/9pfs/9p-util.h

@@ -267,4 +267,10 @@ int pthread_fchdir_np(int fd) __attribute__((weak_import));
 #endif
 #endif
 int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev);
 int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev);
 
 
+/*
+ * Returns a newly allocated string presentation of open() flags, intended
+ * for debugging (tracing) purposes only.
+ */
+char *qemu_open_flags_tostr(int flags);
+
 #endif
 #endif

+ 39 - 6
hw/9pfs/9p.c

@@ -1774,6 +1774,21 @@ static bool same_stat_id(const struct stat *a, const struct stat *b)
     return a->st_dev == b->st_dev && a->st_ino == b->st_ino;
     return a->st_dev == b->st_dev && a->st_ino == b->st_ino;
 }
 }
 
 
+/*
+ * Returns a (newly allocated) comma-separated string presentation of the
+ * passed array for logging (tracing) purpose for trace event "v9fs_walk".
+ *
+ * It is caller's responsibility to free the returned string.
+ */
+static char *trace_v9fs_walk_wnames(V9fsString *wnames, size_t nwnames)
+{
+    g_autofree char **arr = g_malloc0_n(nwnames + 1, sizeof(char *));
+    for (size_t i = 0; i < nwnames; ++i) {
+        arr[i] = wnames[i].data;
+    }
+    return g_strjoinv(", ", arr);
+}
+
 static void coroutine_fn v9fs_walk(void *opaque)
 static void coroutine_fn v9fs_walk(void *opaque)
 {
 {
     int name_idx, nwalked;
     int name_idx, nwalked;
@@ -1787,6 +1802,7 @@ static void coroutine_fn v9fs_walk(void *opaque)
     size_t offset = 7;
     size_t offset = 7;
     int32_t fid, newfid;
     int32_t fid, newfid;
     P9ARRAY_REF(V9fsString) wnames = NULL;
     P9ARRAY_REF(V9fsString) wnames = NULL;
+    g_autofree char *trace_wnames = NULL;
     V9fsFidState *fidp;
     V9fsFidState *fidp;
     V9fsFidState *newfidp = NULL;
     V9fsFidState *newfidp = NULL;
     V9fsPDU *pdu = opaque;
     V9fsPDU *pdu = opaque;
@@ -1800,11 +1816,9 @@ static void coroutine_fn v9fs_walk(void *opaque)
     }
     }
     offset += err;
     offset += err;
 
 
-    trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
-
     if (nwnames > P9_MAXWELEM) {
     if (nwnames > P9_MAXWELEM) {
         err = -EINVAL;
         err = -EINVAL;
-        goto out_nofid;
+        goto out_nofid_nownames;
     }
     }
     if (nwnames) {
     if (nwnames) {
         P9ARRAY_NEW(V9fsString, wnames, nwnames);
         P9ARRAY_NEW(V9fsString, wnames, nwnames);
@@ -1814,15 +1828,23 @@ static void coroutine_fn v9fs_walk(void *opaque)
         for (i = 0; i < nwnames; i++) {
         for (i = 0; i < nwnames; i++) {
             err = pdu_unmarshal(pdu, offset, "s", &wnames[i]);
             err = pdu_unmarshal(pdu, offset, "s", &wnames[i]);
             if (err < 0) {
             if (err < 0) {
-                goto out_nofid;
+                goto out_nofid_nownames;
             }
             }
             if (name_is_illegal(wnames[i].data)) {
             if (name_is_illegal(wnames[i].data)) {
                 err = -ENOENT;
                 err = -ENOENT;
-                goto out_nofid;
+                goto out_nofid_nownames;
             }
             }
             offset += err;
             offset += err;
         }
         }
+        if (trace_event_get_state_backends(TRACE_V9FS_WALK)) {
+            trace_wnames = trace_v9fs_walk_wnames(wnames, nwnames);
+            trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames,
+                            trace_wnames);
+        }
+    } else {
+        trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames, "");
     }
     }
+
     fidp = get_fid(pdu, fid);
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
     if (fidp == NULL) {
         err = -ENOENT;
         err = -ENOENT;
@@ -1957,7 +1979,11 @@ out:
     }
     }
     v9fs_path_free(&dpath);
     v9fs_path_free(&dpath);
     v9fs_path_free(&path);
     v9fs_path_free(&path);
+    goto out_pdu_complete;
+out_nofid_nownames:
+    trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames, "<?>");
 out_nofid:
 out_nofid:
+out_pdu_complete:
     pdu_complete(pdu, err);
     pdu_complete(pdu, err);
 }
 }
 
 
@@ -1982,6 +2008,7 @@ static void coroutine_fn v9fs_open(void *opaque)
     V9fsFidState *fidp;
     V9fsFidState *fidp;
     V9fsPDU *pdu = opaque;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
     V9fsState *s = pdu->s;
+    g_autofree char *trace_oflags = NULL;
 
 
     if (s->proto_version == V9FS_PROTO_2000L) {
     if (s->proto_version == V9FS_PROTO_2000L) {
         err = pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
         err = pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
@@ -1993,7 +2020,13 @@ static void coroutine_fn v9fs_open(void *opaque)
     if (err < 0) {
     if (err < 0) {
         goto out_nofid;
         goto out_nofid;
     }
     }
-    trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
+    if (trace_event_get_state_backends(TRACE_V9FS_OPEN)) {
+        trace_oflags = qemu_open_flags_tostr(
+            (s->proto_version == V9FS_PROTO_2000L) ?
+                dotl_to_open_flags(mode) : omode_to_uflags(mode)
+        );
+        trace_v9fs_open(pdu->tag, pdu->id, fid, mode, trace_oflags);
+    }
 
 
     fidp = get_fid(pdu, fid);
     fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
     if (fidp == NULL) {

+ 1 - 0
hw/9pfs/meson.build

@@ -3,6 +3,7 @@ fs_ss.add(files(
   '9p-local.c',
   '9p-local.c',
   '9p-posix-acl.c',
   '9p-posix-acl.c',
   '9p-synth.c',
   '9p-synth.c',
+  '9p-util-generic.c',
   '9p-xattr-user.c',
   '9p-xattr-user.c',
   '9p-xattr.c',
   '9p-xattr.c',
   '9p.c',
   '9p.c',

+ 2 - 2
hw/9pfs/trace-events

@@ -11,9 +11,9 @@ 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_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(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_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(uint16_t tag, uint8_t id, int32_t fid, int32_t newfid, uint16_t nwnames, const char* wnames) "tag=%d id=%d fid=%d newfid=%d nwnames=%d wnames={%s}"
 v9fs_walk_return(uint16_t tag, uint8_t id, uint16_t nwnames, void* qids) "tag %d id %d nwnames %d qids %p"
 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(uint16_t tag, uint8_t id, int32_t fid, int32_t mode, const char* oflags) "tag=%d id=%d fid=%d mode=%d(%s)"
 v9fs_open_return(uint16_t tag, uint8_t id, uint8_t type, uint32_t version, uint64_t path, int iounit) "tag %u id %u qid={type %u version %u path %"PRIu64"} iounit %d"
 v9fs_open_return(uint16_t tag, uint8_t id, uint8_t type, uint32_t version, uint64_t path, int iounit) "tag %u id %u qid={type %u version %u path %"PRIu64"} iounit %d"
 v9fs_lcreate(uint16_t tag, uint8_t id, int32_t dfid, int32_t flags, int32_t mode, uint32_t gid) "tag %d id %d dfid %d flags %d mode %d gid %u"
 v9fs_lcreate(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, uint8_t type, uint32_t version, uint64_t path, int32_t iounit) "tag %u id %u qid={type %u version %u path %"PRIu64"} iounit %d"
 v9fs_lcreate_return(uint16_t tag, uint8_t id, uint8_t type, uint32_t version, uint64_t path, int32_t iounit) "tag %u id %u qid={type %u version %u path %"PRIu64"} iounit %d"

+ 27 - 22
qemu-options.hx

@@ -1951,32 +1951,37 @@ SRST
         Specifies the tag name to be used by the guest to mount this
         Specifies the tag name to be used by the guest to mount this
         export point.
         export point.
 
 
-    ``multidevs=multidevs``
-        Specifies how to deal with multiple devices being shared with a
-        9p export. Supported behaviours are either "remap", "forbid" or
-        "warn". The latter is the default behaviour on which virtfs 9p
-        expects only one device to be shared with the same export, and
-        if more than one device is shared and accessed via the same 9p
-        export then only a warning message is logged (once) by qemu on
-        host side. In order to avoid file ID collisions on guest you
-        should either create a separate virtfs export for each device to
-        be shared with guests (recommended way) or you might use "remap"
-        instead which allows you to share multiple devices with only one
-        export instead, which is achieved by remapping the original
-        inode numbers from host to guest in a way that would prevent
-        such collisions. Remapping inodes in such use cases is required
+    ``multidevs=remap|forbid|warn``
+        Specifies how to deal with multiple devices being shared with
+        the same 9p export in order to avoid file ID collisions on guest.
+        Supported behaviours are either "remap" (default), "forbid" or
+        "warn".
+
+        ``remap`` : assumes the possibility that more than one device is
+        shared with the same 9p export. Therefore inode numbers from host
+        are remapped for guest in a way that would prevent file ID
+        collisions on guest. Remapping inodes in such cases is required
         because the original device IDs from host are never passed and
         because the original device IDs from host are never passed and
         exposed on guest. Instead all files of an export shared with
         exposed on guest. Instead all files of an export shared with
-        virtfs always share the same device id on guest. So two files
+        virtfs always share the same device ID on guest. So two files
         with identical inode numbers but from actually different devices
         with identical inode numbers but from actually different devices
         on host would otherwise cause a file ID collision and hence
         on host would otherwise cause a file ID collision and hence
-        potential misbehaviours on guest. "forbid" on the other hand
-        assumes like "warn" that only one device is shared by the same
-        export, however it will not only log a warning message but also
-        deny access to additional devices on guest. Note though that
-        "forbid" does currently not block all possible file access
-        operations (e.g. readdir() would still return entries from other
-        devices).
+        potential severe misbehaviours on guest.
+
+        ``warn`` : virtfs 9p expects only one device to be shared with
+        the same export. If however more than one device is shared and
+        accessed via the same 9p export then only a warning message is
+        logged (once) by qemu on host side. No further action is performed
+        in this case that would prevent file ID collisions on guest. This
+        could thus lead to severe misbehaviours in this case like wrong
+        files being accessed and data corruption on the exported tree.
+
+        ``forbid`` : assumes like "warn" that only one device is shared
+        by the same 9p export, however it will not only log a warning
+        message but also deny access to additional devices on guest. Note
+        though that "forbid" does currently not block all possible file
+        access operations (e.g. readdir() would still return entries from
+        other devices).
 ERST
 ERST
 
 
 DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi,
 DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi,