aboutsummaryrefslogtreecommitdiff
path: root/hw/9pfs
diff options
context:
space:
mode:
Diffstat (limited to 'hw/9pfs')
-rw-r--r--hw/9pfs/9p-local.c52
-rw-r--r--hw/9pfs/9p-proxy.c1279
-rw-r--r--hw/9pfs/9p-proxy.h101
-rw-r--r--hw/9pfs/9p-synth.c24
-rw-r--r--hw/9pfs/9p-util-generic.c50
-rw-r--r--hw/9pfs/9p-util.h34
-rw-r--r--hw/9pfs/9p.c124
-rw-r--r--hw/9pfs/9p.h2
-rw-r--r--hw/9pfs/codir.c7
-rw-r--r--hw/9pfs/cofile.c7
-rw-r--r--hw/9pfs/cofs.c37
-rw-r--r--hw/9pfs/coth.h4
-rw-r--r--hw/9pfs/meson.build2
-rw-r--r--hw/9pfs/trace-events4
-rw-r--r--hw/9pfs/virtio-9p-device.c7
15 files changed, 298 insertions, 1436 deletions
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index 1b1f3b9..31e2162 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -766,16 +766,19 @@ out:
return err;
}
-static int local_fstat(FsContext *fs_ctx, int fid_type,
- V9fsFidOpenState *fs, struct stat *stbuf)
+static int local_fid_fd(int fid_type, V9fsFidOpenState *fs)
{
- int err, fd;
-
if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir.stream);
+ return dirfd(fs->dir.stream);
} else {
- fd = fs->fd;
+ return fs->fd;
}
+}
+
+static int local_fstat(FsContext *fs_ctx, int fid_type,
+ V9fsFidOpenState *fs, struct stat *stbuf)
+{
+ int err, fd = local_fid_fd(fid_type, fs);
err = fstat(fd, stbuf);
if (err) {
@@ -1039,6 +1042,14 @@ static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
return ret;
}
+static int local_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs,
+ off_t size)
+{
+ int fd = local_fid_fd(fid_type, fs);
+
+ return ftruncate(fd, size);
+}
+
static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
char *dirpath = g_path_get_dirname(fs_path->data);
@@ -1089,6 +1100,14 @@ out:
return ret;
}
+static int local_futimens(FsContext *s, int fid_type, V9fsFidOpenState *fs,
+ const struct timespec *times)
+{
+ int fd = local_fid_fd(fid_type, fs);
+
+ return qemu_futimens(fd, times);
+}
+
static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
int flags)
{
@@ -1167,13 +1186,7 @@ out:
static int local_fsync(FsContext *ctx, int fid_type,
V9fsFidOpenState *fs, int datasync)
{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir.stream);
- } else {
- fd = fs->fd;
- }
+ int fd = local_fid_fd(fid_type, fs);
if (datasync) {
return qemu_fdatasync(fd);
@@ -1538,6 +1551,9 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
"[remap|forbid|warn]\n");
return -1;
}
+ } else {
+ fse->export_flags &= ~V9FS_FORBID_MULTIDEVS;
+ fse->export_flags |= V9FS_REMAP_INODES;
}
if (!path) {
@@ -1572,6 +1588,13 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
return 0;
}
+static bool local_has_valid_file_handle(int fid_type, V9fsFidOpenState *fs)
+{
+ return
+ (fid_type == P9_FID_FILE && fs->fd != -1) ||
+ (fid_type == P9_FID_DIR && fs->dir.stream != NULL);
+}
+
FileOperations local_ops = {
.parse_opts = local_parse_opts,
.init = local_init,
@@ -1609,4 +1632,7 @@ FileOperations local_ops = {
.name_to_path = local_name_to_path,
.renameat = local_renameat,
.unlinkat = local_unlinkat,
+ .has_valid_file_handle = local_has_valid_file_handle,
+ .ftruncate = local_ftruncate,
+ .futimens = local_futimens,
};
diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c
deleted file mode 100644
index 7aac49a..0000000
--- a/hw/9pfs/9p-proxy.c
+++ /dev/null
@@ -1,1279 +0,0 @@
-/*
- * 9p Proxy callback
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * M. Mohan Kumar <mohan@in.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-
-/*
- * Not so fast! You might want to read the 9p developer docs first:
- * https://wiki.qemu.org/Documentation/9p
- */
-
-/*
- * NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be
- * removed in a future version of QEMU!
- */
-
-#include "qemu/osdep.h"
-#include <sys/socket.h>
-#include <sys/un.h>
-#include "9p.h"
-#include "qapi/error.h"
-#include "qemu/cutils.h"
-#include "qemu/error-report.h"
-#include "qemu/option.h"
-#include "fsdev/qemu-fsdev.h"
-#include "9p-proxy.h"
-
-typedef struct V9fsProxy {
- int sockfd;
- QemuMutex mutex;
- struct iovec in_iovec;
- struct iovec out_iovec;
-} V9fsProxy;
-
-/*
- * Return received file descriptor on success in *status.
- * errno is also returned on *status (which will be < 0)
- * return < 0 on transport error.
- */
-static int v9fs_receivefd(int sockfd, int *status)
-{
- struct iovec iov;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- int retval, data, fd;
- union MsgControl msg_control;
-
- iov.iov_base = &data;
- iov.iov_len = sizeof(data);
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = &msg_control;
- msg.msg_controllen = sizeof(msg_control);
-
- do {
- retval = recvmsg(sockfd, &msg, 0);
- } while (retval < 0 && errno == EINTR);
- if (retval <= 0) {
- return retval;
- }
- /*
- * data is set to V9FS_FD_VALID, if ancillary data is sent. If this
- * request doesn't need ancillary data (fd) or an error occurred,
- * data is set to negative errno value.
- */
- if (data != V9FS_FD_VALID) {
- *status = data;
- return 0;
- }
- /*
- * File descriptor (fd) is sent in the ancillary data. Check if we
- * indeed received it. One of the reasons to fail to receive it is if
- * we exceeded the maximum number of file descriptors!
- */
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
- cmsg->cmsg_level != SOL_SOCKET ||
- cmsg->cmsg_type != SCM_RIGHTS) {
- continue;
- }
- fd = *((int *)CMSG_DATA(cmsg));
- *status = fd;
- return 0;
- }
- *status = -ENFILE; /* Ancillary data sent but not received */
- return 0;
-}
-
-static ssize_t socket_read(int sockfd, void *buff, size_t size)
-{
- ssize_t retval, total = 0;
-
- while (size) {
- retval = read(sockfd, buff, size);
- if (retval == 0) {
- return -EIO;
- }
- if (retval < 0) {
- if (errno == EINTR) {
- continue;
- }
- return -errno;
- }
- size -= retval;
- buff += retval;
- total += retval;
- }
- return total;
-}
-
-/* Converts proxy_statfs to VFS statfs structure */
-static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs)
-{
- memset(stfs, 0, sizeof(*stfs));
- stfs->f_type = prstfs->f_type;
- stfs->f_bsize = prstfs->f_bsize;
- stfs->f_blocks = prstfs->f_blocks;
- stfs->f_bfree = prstfs->f_bfree;
- stfs->f_bavail = prstfs->f_bavail;
- stfs->f_files = prstfs->f_files;
- stfs->f_ffree = prstfs->f_ffree;
-#ifdef CONFIG_DARWIN
- /* f_namelen and f_frsize do not exist on Darwin */
- stfs->f_fsid.val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU;
- stfs->f_fsid.val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU;
-#else
- stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU;
- stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU;
- stfs->f_namelen = prstfs->f_namelen;
- stfs->f_frsize = prstfs->f_frsize;
-#endif
-}
-
-/* Converts proxy_stat structure to VFS stat structure */
-static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat)
-{
- memset(stbuf, 0, sizeof(*stbuf));
- stbuf->st_dev = prstat->st_dev;
- stbuf->st_ino = prstat->st_ino;
- stbuf->st_nlink = prstat->st_nlink;
- stbuf->st_mode = prstat->st_mode;
- stbuf->st_uid = prstat->st_uid;
- stbuf->st_gid = prstat->st_gid;
- stbuf->st_rdev = prstat->st_rdev;
- stbuf->st_size = prstat->st_size;
- stbuf->st_blksize = prstat->st_blksize;
- stbuf->st_blocks = prstat->st_blocks;
- stbuf->st_atime = prstat->st_atim_sec;
- stbuf->st_mtime = prstat->st_mtim_sec;
- stbuf->st_ctime = prstat->st_ctim_sec;
-#ifdef CONFIG_DARWIN
- stbuf->st_atimespec.tv_sec = prstat->st_atim_sec;
- stbuf->st_mtimespec.tv_sec = prstat->st_mtim_sec;
- stbuf->st_ctimespec.tv_sec = prstat->st_ctim_sec;
- stbuf->st_atimespec.tv_nsec = prstat->st_atim_nsec;
- stbuf->st_mtimespec.tv_nsec = prstat->st_mtim_nsec;
- stbuf->st_ctimespec.tv_nsec = prstat->st_ctim_nsec;
-#else
- stbuf->st_atim.tv_sec = prstat->st_atim_sec;
- stbuf->st_mtim.tv_sec = prstat->st_mtim_sec;
- stbuf->st_ctim.tv_sec = prstat->st_ctim_sec;
- stbuf->st_atim.tv_nsec = prstat->st_atim_nsec;
- stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec;
- stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec;
-#endif
-}
-
-/*
- * Response contains two parts
- * {header, data}
- * header.type == T_ERROR, data -> -errno
- * header.type == T_SUCCESS, data -> response
- * size of errno/response is given by header.size
- * returns < 0, on transport error. response is
- * valid only if status >= 0.
- */
-static int v9fs_receive_response(V9fsProxy *proxy, int type,
- int *status, void *response)
-{
- int retval;
- ProxyHeader header;
- struct iovec *reply = &proxy->in_iovec;
-
- *status = 0;
- reply->iov_len = 0;
- retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len = PROXY_HDR_SZ;
- retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
- assert(retval == 4 * 2);
- /*
- * if response size > PROXY_MAX_IO_SZ, read the response but ignore it and
- * return -ENOBUFS
- */
- if (header.size > PROXY_MAX_IO_SZ) {
- int count;
- while (header.size > 0) {
- count = MIN(PROXY_MAX_IO_SZ, header.size);
- count = socket_read(proxy->sockfd, reply->iov_base, count);
- if (count < 0) {
- return count;
- }
- header.size -= count;
- }
- *status = -ENOBUFS;
- return 0;
- }
-
- retval = socket_read(proxy->sockfd,
- reply->iov_base + PROXY_HDR_SZ, header.size);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len += header.size;
- /* there was an error during processing request */
- if (header.type == T_ERROR) {
- int ret;
- ret = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
- assert(ret == 4);
- return 0;
- }
-
- switch (type) {
- case T_LSTAT: {
- ProxyStat prstat;
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ,
- "qqqdddqqqqqqqqqq", &prstat.st_dev,
- &prstat.st_ino, &prstat.st_nlink,
- &prstat.st_mode, &prstat.st_uid,
- &prstat.st_gid, &prstat.st_rdev,
- &prstat.st_size, &prstat.st_blksize,
- &prstat.st_blocks,
- &prstat.st_atim_sec, &prstat.st_atim_nsec,
- &prstat.st_mtim_sec, &prstat.st_mtim_nsec,
- &prstat.st_ctim_sec, &prstat.st_ctim_nsec);
- assert(retval == 8 * 3 + 4 * 3 + 8 * 10);
- prstat_to_stat(response, &prstat);
- break;
- }
- case T_STATFS: {
- ProxyStatFS prstfs;
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ,
- "qqqqqqqqqqq", &prstfs.f_type,
- &prstfs.f_bsize, &prstfs.f_blocks,
- &prstfs.f_bfree, &prstfs.f_bavail,
- &prstfs.f_files, &prstfs.f_ffree,
- &prstfs.f_fsid[0], &prstfs.f_fsid[1],
- &prstfs.f_namelen, &prstfs.f_frsize);
- assert(retval == 8 * 11);
- prstatfs_to_statfs(response, &prstfs);
- break;
- }
- case T_READLINK: {
- V9fsString target;
- v9fs_string_init(&target);
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &target);
- strcpy(response, target.data);
- v9fs_string_free(&target);
- break;
- }
- case T_LGETXATTR:
- case T_LLISTXATTR: {
- V9fsString xattr;
- v9fs_string_init(&xattr);
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &xattr);
- memcpy(response, xattr.data, xattr.size);
- v9fs_string_free(&xattr);
- break;
- }
- case T_GETVERSION:
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response);
- assert(retval == 8);
- break;
- default:
- return -1;
- }
- if (retval < 0) {
- *status = retval;
- }
- return 0;
-}
-
-/*
- * return < 0 on transport error.
- * *status is valid only if return >= 0
- */
-static int v9fs_receive_status(V9fsProxy *proxy,
- struct iovec *reply, int *status)
-{
- int retval;
- ProxyHeader header;
-
- *status = 0;
- reply->iov_len = 0;
- retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len = PROXY_HDR_SZ;
- retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
- assert(retval == 4 * 2);
- retval = socket_read(proxy->sockfd,
- reply->iov_base + PROXY_HDR_SZ, header.size);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len += header.size;
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
- assert(retval == 4);
- return 0;
-}
-
-/*
- * Proxy->header and proxy->request written to socket by QEMU process.
- * This request read by proxy helper process
- * returns 0 on success and -errno on error
- */
-static int v9fs_request(V9fsProxy *proxy, int type, void *response, ...)
-{
- dev_t rdev;
- va_list ap;
- int size = 0;
- int retval = 0;
- uint64_t offset;
- ProxyHeader header = { 0, 0};
- struct timespec spec[2];
- int flags, mode, uid, gid;
- V9fsString *name, *value;
- V9fsString *path, *oldpath;
- struct iovec *iovec = NULL, *reply = NULL;
-
- qemu_mutex_lock(&proxy->mutex);
-
- if (proxy->sockfd == -1) {
- retval = -EIO;
- goto err_out;
- }
- iovec = &proxy->out_iovec;
- reply = &proxy->in_iovec;
- va_start(ap, response);
- switch (type) {
- case T_OPEN:
- path = va_arg(ap, V9fsString *);
- flags = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, flags);
- if (retval > 0) {
- header.size = retval;
- header.type = T_OPEN;
- }
- break;
- case T_CREATE:
- path = va_arg(ap, V9fsString *);
- flags = va_arg(ap, int);
- mode = va_arg(ap, int);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdddd", path,
- flags, mode, uid, gid);
- if (retval > 0) {
- header.size = retval;
- header.type = T_CREATE;
- }
- break;
- case T_MKNOD:
- path = va_arg(ap, V9fsString *);
- mode = va_arg(ap, int);
- rdev = va_arg(ap, long int);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsdq",
- uid, gid, path, mode, rdev);
- if (retval > 0) {
- header.size = retval;
- header.type = T_MKNOD;
- }
- break;
- case T_MKDIR:
- path = va_arg(ap, V9fsString *);
- mode = va_arg(ap, int);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsd",
- uid, gid, path, mode);
- if (retval > 0) {
- header.size = retval;
- header.type = T_MKDIR;
- }
- break;
- case T_SYMLINK:
- oldpath = va_arg(ap, V9fsString *);
- path = va_arg(ap, V9fsString *);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddss",
- uid, gid, oldpath, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_SYMLINK;
- }
- break;
- case T_LINK:
- oldpath = va_arg(ap, V9fsString *);
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss",
- oldpath, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LINK;
- }
- break;
- case T_LSTAT:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LSTAT;
- }
- break;
- case T_READLINK:
- path = va_arg(ap, V9fsString *);
- size = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, size);
- if (retval > 0) {
- header.size = retval;
- header.type = T_READLINK;
- }
- break;
- case T_STATFS:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_STATFS;
- }
- break;
- case T_CHMOD:
- path = va_arg(ap, V9fsString *);
- mode = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, mode);
- if (retval > 0) {
- header.size = retval;
- header.type = T_CHMOD;
- }
- break;
- case T_CHOWN:
- path = va_arg(ap, V9fsString *);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdd", path, uid, gid);
- if (retval > 0) {
- header.size = retval;
- header.type = T_CHOWN;
- }
- break;
- case T_TRUNCATE:
- path = va_arg(ap, V9fsString *);
- offset = va_arg(ap, uint64_t);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sq", path, offset);
- if (retval > 0) {
- header.size = retval;
- header.type = T_TRUNCATE;
- }
- break;
- case T_UTIME:
- path = va_arg(ap, V9fsString *);
- spec[0].tv_sec = va_arg(ap, long);
- spec[0].tv_nsec = va_arg(ap, long);
- spec[1].tv_sec = va_arg(ap, long);
- spec[1].tv_nsec = va_arg(ap, long);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sqqqq", path,
- spec[0].tv_sec, spec[1].tv_nsec,
- spec[1].tv_sec, spec[1].tv_nsec);
- if (retval > 0) {
- header.size = retval;
- header.type = T_UTIME;
- }
- break;
- case T_RENAME:
- oldpath = va_arg(ap, V9fsString *);
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", oldpath, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_RENAME;
- }
- break;
- case T_REMOVE:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_REMOVE;
- }
- break;
- case T_LGETXATTR:
- size = va_arg(ap, int);
- path = va_arg(ap, V9fsString *);
- name = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ,
- "dss", size, path, name);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LGETXATTR;
- }
- break;
- case T_LLISTXATTR:
- size = va_arg(ap, int);
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ds", size, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LLISTXATTR;
- }
- break;
- case T_LSETXATTR:
- path = va_arg(ap, V9fsString *);
- name = va_arg(ap, V9fsString *);
- value = va_arg(ap, V9fsString *);
- size = va_arg(ap, int);
- flags = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sssdd",
- path, name, value, size, flags);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LSETXATTR;
- }
- break;
- case T_LREMOVEXATTR:
- path = va_arg(ap, V9fsString *);
- name = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", path, name);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LREMOVEXATTR;
- }
- break;
- case T_GETVERSION:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_GETVERSION;
- }
- break;
- default:
- error_report("Invalid type %d", type);
- retval = -EINVAL;
- break;
- }
- va_end(ap);
-
- if (retval < 0) {
- goto err_out;
- }
-
- /* marshal the header details */
- retval = proxy_marshal(iovec, 0, "dd", header.type, header.size);
- assert(retval == 4 * 2);
- header.size += PROXY_HDR_SZ;
-
- retval = qemu_write_full(proxy->sockfd, iovec->iov_base, header.size);
- if (retval != header.size) {
- goto close_error;
- }
-
- switch (type) {
- case T_OPEN:
- case T_CREATE:
- /*
- * A file descriptor is returned as response for
- * T_OPEN,T_CREATE on success
- */
- if (v9fs_receivefd(proxy->sockfd, &retval) < 0) {
- goto close_error;
- }
- break;
- case T_MKNOD:
- case T_MKDIR:
- case T_SYMLINK:
- case T_LINK:
- case T_CHMOD:
- case T_CHOWN:
- case T_RENAME:
- case T_TRUNCATE:
- case T_UTIME:
- case T_REMOVE:
- case T_LSETXATTR:
- case T_LREMOVEXATTR:
- if (v9fs_receive_status(proxy, reply, &retval) < 0) {
- goto close_error;
- }
- break;
- case T_LSTAT:
- case T_READLINK:
- case T_STATFS:
- case T_GETVERSION:
- if (v9fs_receive_response(proxy, type, &retval, response) < 0) {
- goto close_error;
- }
- break;
- case T_LGETXATTR:
- case T_LLISTXATTR:
- if (!size) {
- if (v9fs_receive_status(proxy, reply, &retval) < 0) {
- goto close_error;
- }
- } else {
- if (v9fs_receive_response(proxy, type, &retval, response) < 0) {
- goto close_error;
- }
- }
- break;
- }
-
-err_out:
- qemu_mutex_unlock(&proxy->mutex);
- return retval;
-
-close_error:
- close(proxy->sockfd);
- proxy->sockfd = -1;
- qemu_mutex_unlock(&proxy->mutex);
- return -EIO;
-}
-
-static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, fs_path);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return retval;
-}
-
-static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
- char *buf, size_t bufsz)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_READLINK, buf, fs_path, bufsz);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return strlen(buf);
-}
-
-static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return close(fs->fd);
-}
-
-static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return closedir(fs->dir.stream);
-}
-
-static int proxy_open(FsContext *ctx, V9fsPath *fs_path,
- int flags, V9fsFidOpenState *fs)
-{
- fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, flags);
- if (fs->fd < 0) {
- errno = -fs->fd;
- fs->fd = -1;
- }
- return fs->fd;
-}
-
-static int proxy_opendir(FsContext *ctx,
- V9fsPath *fs_path, V9fsFidOpenState *fs)
-{
- int serrno, fd;
-
- fs->dir.stream = NULL;
- fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, O_DIRECTORY);
- if (fd < 0) {
- errno = -fd;
- return -1;
- }
- fs->dir.stream = fdopendir(fd);
- if (!fs->dir.stream) {
- serrno = errno;
- close(fd);
- errno = serrno;
- return -1;
- }
- return 0;
-}
-
-static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- rewinddir(fs->dir.stream);
-}
-
-static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return telldir(fs->dir.stream);
-}
-
-static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- struct dirent *entry;
- entry = readdir(fs->dir.stream);
-#ifdef CONFIG_DARWIN
- if (!entry) {
- return NULL;
- }
- int td;
- td = telldir(fs->dir.stream);
- /* If telldir fails, fail the entire readdir call */
- if (td < 0) {
- return NULL;
- }
- entry->d_seekoff = td;
-#endif
- return entry;
-}
-
-static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
-{
- seekdir(fs->dir.stream, off);
-}
-
-static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
- ssize_t ret;
-#ifdef CONFIG_PREADV
- ret = preadv(fs->fd, iov, iovcnt, offset);
-#else
- ret = lseek(fs->fd, offset, SEEK_SET);
- if (ret >= 0) {
- ret = readv(fs->fd, iov, iovcnt);
- }
-#endif
- return ret;
-}
-
-static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
- ssize_t ret;
-
-#ifdef CONFIG_PREADV
- ret = pwritev(fs->fd, iov, iovcnt, offset);
-#else
- ret = lseek(fs->fd, offset, SEEK_SET);
- if (ret >= 0) {
- ret = writev(fs->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 specified.
- */
- sync_file_range(fs->fd, offset, ret,
- SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
- }
-#endif
- return ret;
-}
-
-static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, fs_path,
- credp->fc_mode);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- int retval;
- V9fsString fullname;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
-
- retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, &fullname,
- credp->fc_mode, credp->fc_rdev,
- credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- int retval;
- V9fsString fullname;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
-
- retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, &fullname,
- credp->fc_mode, credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_fstat(FsContext *fs_ctx, int fid_type,
- V9fsFidOpenState *fs, struct stat *stbuf)
-{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir.stream);
- } else {
- fd = fs->fd;
- }
- return fstat(fd, stbuf);
-}
-
-static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
- int flags, FsCred *credp, V9fsFidOpenState *fs)
-{
- V9fsString fullname;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
-
- fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, &fullname, flags,
- credp->fc_mode, credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- if (fs->fd < 0) {
- errno = -fs->fd;
- fs->fd = -1;
- }
- return fs->fd;
-}
-
-static int proxy_symlink(FsContext *fs_ctx, const char *oldpath,
- V9fsPath *dir_path, const char *name, FsCred *credp)
-{
- int retval;
- V9fsString fullname, target;
-
- v9fs_string_init(&fullname);
- v9fs_string_init(&target);
-
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- v9fs_string_sprintf(&target, "%s", oldpath);
-
- retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, &target, &fullname,
- credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- v9fs_string_free(&target);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_link(FsContext *ctx, V9fsPath *oldpath,
- V9fsPath *dirpath, const char *name)
-{
- int retval;
- V9fsString newpath;
-
- v9fs_string_init(&newpath);
- v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
-
- retval = v9fs_request(ctx->private, T_LINK, NULL, oldpath, &newpath);
- v9fs_string_free(&newpath);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
-{
- int retval;
-
- retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, fs_path, size);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return 0;
-}
-
-static int proxy_rename(FsContext *ctx, const char *oldpath,
- const char *newpath)
-{
- int retval;
- V9fsString oldname, newname;
-
- v9fs_string_init(&oldname);
- v9fs_string_init(&newname);
-
- v9fs_string_sprintf(&oldname, "%s", oldpath);
- v9fs_string_sprintf(&newname, "%s", newpath);
- retval = v9fs_request(ctx->private, T_RENAME, NULL, &oldname, &newname);
- v9fs_string_free(&oldname);
- v9fs_string_free(&newname);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, fs_path,
- credp->fc_uid, credp->fc_gid);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_utimensat(FsContext *s, V9fsPath *fs_path,
- const struct timespec *buf)
-{
- int retval;
- retval = v9fs_request(s->private, T_UTIME, NULL, fs_path,
- buf[0].tv_sec, buf[0].tv_nsec,
- buf[1].tv_sec, buf[1].tv_nsec);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_remove(FsContext *ctx, const char *path)
-{
- int retval;
- V9fsString name;
- v9fs_string_init(&name);
- v9fs_string_sprintf(&name, "%s", path);
- retval = v9fs_request(ctx->private, T_REMOVE, NULL, &name);
- v9fs_string_free(&name);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_fsync(FsContext *ctx, int fid_type,
- V9fsFidOpenState *fs, int datasync)
-{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir.stream);
- } else {
- fd = fs->fd;
- }
-
- if (datasync) {
- return qemu_fdatasync(fd);
- } else {
- return fsync(fd);
- }
-}
-
-static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
-{
- int retval;
- retval = v9fs_request(s->private, T_STATFS, stbuf, fs_path);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return retval;
-}
-
-static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name, void *value, size_t size)
-{
- int retval;
- V9fsString xname;
-
- v9fs_string_init(&xname);
- v9fs_string_sprintf(&xname, "%s", name);
- retval = v9fs_request(ctx->private, T_LGETXATTR, value, size, fs_path,
- &xname);
- v9fs_string_free(&xname);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path,
- void *value, size_t size)
-{
- int retval;
- retval = v9fs_request(ctx->private, T_LLISTXATTR, value, size, fs_path);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
- void *value, size_t size, int flags)
-{
- int retval;
- V9fsString xname, xvalue;
-
- v9fs_string_init(&xname);
- v9fs_string_sprintf(&xname, "%s", name);
-
- v9fs_string_init(&xvalue);
- xvalue.size = size;
- xvalue.data = g_malloc(size);
- memcpy(xvalue.data, value, size);
-
- retval = v9fs_request(ctx->private, T_LSETXATTR, value, fs_path, &xname,
- &xvalue, size, flags);
- v9fs_string_free(&xname);
- v9fs_string_free(&xvalue);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name)
-{
- int retval;
- V9fsString xname;
-
- v9fs_string_init(&xname);
- v9fs_string_sprintf(&xname, "%s", name);
- retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, fs_path, &xname);
- v9fs_string_free(&xname);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path,
- const char *name, V9fsPath *target)
-{
- if (dir_path) {
- v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
- } else {
- v9fs_path_sprintf(target, "%s", name);
- }
- return 0;
-}
-
-static int proxy_renameat(FsContext *ctx, V9fsPath *olddir,
- const char *old_name, V9fsPath *newdir,
- const char *new_name)
-{
- int ret;
- V9fsString old_full_name, new_full_name;
-
- v9fs_string_init(&old_full_name);
- v9fs_string_init(&new_full_name);
-
- v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
- v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
-
- ret = proxy_rename(ctx, old_full_name.data, new_full_name.data);
- v9fs_string_free(&old_full_name);
- v9fs_string_free(&new_full_name);
- return ret;
-}
-
-static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir,
- const char *name, int flags)
-{
- int ret;
- V9fsString fullname;
- v9fs_string_init(&fullname);
-
- v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
- ret = proxy_remove(ctx, fullname.data);
- v9fs_string_free(&fullname);
-
- return ret;
-}
-
-static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path,
- mode_t st_mode, uint64_t *st_gen)
-{
- int err;
-
- /* 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)) {
- errno = ENOTTY;
- return -1;
- }
- err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, path);
- if (err < 0) {
- errno = -err;
- err = -1;
- }
- return err;
-}
-
-static int connect_namedsocket(const char *path, Error **errp)
-{
- int sockfd;
- struct sockaddr_un helper;
-
- if (strlen(path) >= sizeof(helper.sun_path)) {
- error_setg(errp, "socket name too long");
- return -1;
- }
- sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sockfd < 0) {
- error_setg_errno(errp, errno, "failed to create client socket");
- return -1;
- }
- strcpy(helper.sun_path, path);
- helper.sun_family = AF_UNIX;
- if (connect(sockfd, (struct sockaddr *)&helper, sizeof(helper)) < 0) {
- error_setg_errno(errp, errno, "failed to connect to '%s'", path);
- close(sockfd);
- return -1;
- }
-
- /* remove the socket for security reasons */
- unlink(path);
- return sockfd;
-}
-
-static void error_append_socket_sockfd_hint(Error *const *errp)
-{
- error_append_hint(errp, "Either specify socket=/some/path where /some/path"
- " points to a listening AF_UNIX socket or sock_fd=fd"
- " where fd is a file descriptor to a connected AF_UNIX"
- " socket\n");
-}
-
-static int proxy_parse_opts(QemuOpts *opts, FsDriverEntry *fs, Error **errp)
-{
- const char *socket = qemu_opt_get(opts, "socket");
- const char *sock_fd = qemu_opt_get(opts, "sock_fd");
-
- if (!socket && !sock_fd) {
- error_setg(errp, "both socket and sock_fd properties are missing");
- error_append_socket_sockfd_hint(errp);
- return -1;
- }
- if (socket && sock_fd) {
- error_setg(errp, "both socket and sock_fd properties are set");
- error_append_socket_sockfd_hint(errp);
- return -1;
- }
- if (socket) {
- fs->path = g_strdup(socket);
- fs->export_flags |= V9FS_PROXY_SOCK_NAME;
- } else {
- fs->path = g_strdup(sock_fd);
- fs->export_flags |= V9FS_PROXY_SOCK_FD;
- }
- return 0;
-}
-
-static int proxy_init(FsContext *ctx, Error **errp)
-{
- V9fsProxy *proxy = g_new(V9fsProxy, 1);
- int sock_id;
-
- if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
- sock_id = connect_namedsocket(ctx->fs_root, errp);
- } else {
- sock_id = atoi(ctx->fs_root);
- if (sock_id < 0) {
- error_setg(errp, "socket descriptor not initialized");
- }
- }
- if (sock_id < 0) {
- g_free(proxy);
- return -1;
- }
- g_free(ctx->fs_root);
- ctx->fs_root = NULL;
-
- proxy->in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
- proxy->in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
- proxy->out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
- proxy->out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
-
- ctx->private = proxy;
- proxy->sockfd = sock_id;
- qemu_mutex_init(&proxy->mutex);
-
- ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
- ctx->exops.get_st_gen = proxy_ioc_getversion;
- return 0;
-}
-
-static void proxy_cleanup(FsContext *ctx)
-{
- V9fsProxy *proxy = ctx->private;
-
- if (!proxy) {
- return;
- }
-
- g_free(proxy->out_iovec.iov_base);
- g_free(proxy->in_iovec.iov_base);
- if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
- close(proxy->sockfd);
- }
- g_free(proxy);
-}
-
-FileOperations proxy_ops = {
- .parse_opts = proxy_parse_opts,
- .init = proxy_init,
- .cleanup = proxy_cleanup,
- .lstat = proxy_lstat,
- .readlink = proxy_readlink,
- .close = proxy_close,
- .closedir = proxy_closedir,
- .open = proxy_open,
- .opendir = proxy_opendir,
- .rewinddir = proxy_rewinddir,
- .telldir = proxy_telldir,
- .readdir = proxy_readdir,
- .seekdir = proxy_seekdir,
- .preadv = proxy_preadv,
- .pwritev = proxy_pwritev,
- .chmod = proxy_chmod,
- .mknod = proxy_mknod,
- .mkdir = proxy_mkdir,
- .fstat = proxy_fstat,
- .open2 = proxy_open2,
- .symlink = proxy_symlink,
- .link = proxy_link,
- .truncate = proxy_truncate,
- .rename = proxy_rename,
- .chown = proxy_chown,
- .utimensat = proxy_utimensat,
- .remove = proxy_remove,
- .fsync = proxy_fsync,
- .statfs = proxy_statfs,
- .lgetxattr = proxy_lgetxattr,
- .llistxattr = proxy_llistxattr,
- .lsetxattr = proxy_lsetxattr,
- .lremovexattr = proxy_lremovexattr,
- .name_to_path = proxy_name_to_path,
- .renameat = proxy_renameat,
- .unlinkat = proxy_unlinkat,
-};
diff --git a/hw/9pfs/9p-proxy.h b/hw/9pfs/9p-proxy.h
deleted file mode 100644
index 9be4718..0000000
--- a/hw/9pfs/9p-proxy.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 9p Proxy callback
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * M. Mohan Kumar <mohan@in.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-
-/*
- * NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be
- * removed in a future version of QEMU!
- */
-
-#ifndef QEMU_9P_PROXY_H
-#define QEMU_9P_PROXY_H
-
-#define PROXY_MAX_IO_SZ (64 * 1024)
-#define V9FS_FD_VALID INT_MAX
-
-/*
- * proxy iovec only support one element and
- * marsha/unmarshal doesn't do little endian conversion.
- */
-#define proxy_unmarshal(in_sg, offset, fmt, args...) \
- v9fs_iov_unmarshal(in_sg, 1, offset, 0, fmt, ##args)
-#define proxy_marshal(out_sg, offset, fmt, args...) \
- v9fs_iov_marshal(out_sg, 1, offset, 0, fmt, ##args)
-
-union MsgControl {
- struct cmsghdr cmsg;
- char control[CMSG_SPACE(sizeof(int))];
-};
-
-typedef struct {
- uint32_t type;
- uint32_t size;
-} ProxyHeader;
-
-#define PROXY_HDR_SZ (sizeof(ProxyHeader))
-
-enum {
- T_SUCCESS = 0,
- T_ERROR,
- T_OPEN,
- T_CREATE,
- T_MKNOD,
- T_MKDIR,
- T_SYMLINK,
- T_LINK,
- T_LSTAT,
- T_READLINK,
- T_STATFS,
- T_CHMOD,
- T_CHOWN,
- T_TRUNCATE,
- T_UTIME,
- T_RENAME,
- T_REMOVE,
- T_LGETXATTR,
- T_LLISTXATTR,
- T_LSETXATTR,
- T_LREMOVEXATTR,
- T_GETVERSION,
-};
-
-typedef struct {
- uint64_t st_dev;
- uint64_t st_ino;
- uint64_t st_nlink;
- uint32_t st_mode;
- uint32_t st_uid;
- uint32_t st_gid;
- uint64_t st_rdev;
- uint64_t st_size;
- uint64_t st_blksize;
- uint64_t st_blocks;
- uint64_t st_atim_sec;
- uint64_t st_atim_nsec;
- uint64_t st_mtim_sec;
- uint64_t st_mtim_nsec;
- uint64_t st_ctim_sec;
- uint64_t st_ctim_nsec;
-} ProxyStat;
-
-typedef struct {
- uint64_t f_type;
- uint64_t f_bsize;
- uint64_t f_blocks;
- uint64_t f_bfree;
- uint64_t f_bavail;
- uint64_t f_files;
- uint64_t f_ffree;
- uint64_t f_fsid[2];
- uint64_t f_namelen;
- uint64_t f_frsize;
-} ProxyStatFS;
-#endif
diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c
index 0ac79a5..9cd1884 100644
--- a/hw/9pfs/9p-synth.c
+++ b/hw/9pfs/9p-synth.c
@@ -24,7 +24,7 @@
#include "qemu/rcu.h"
#include "qemu/rcu_queue.h"
#include "qemu/cutils.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
/* Root node for synth file system */
static V9fsSynthNode synth_root = {
@@ -356,6 +356,13 @@ static int synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset)
return -1;
}
+static int synth_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs,
+ off_t size)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
static int synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
{
errno = EPERM;
@@ -417,6 +424,13 @@ static int synth_utimensat(FsContext *fs_ctx, V9fsPath *path,
return 0;
}
+static int synth_futimens(FsContext *fs_ctx, int fid_type, V9fsFidOpenState *fs,
+ const struct timespec *buf)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
static int synth_remove(FsContext *ctx, const char *path)
{
errno = EPERM;
@@ -615,6 +629,11 @@ static int synth_init(FsContext *ctx, Error **errp)
return 0;
}
+static bool synth_has_valid_file_handle(int fid_type, V9fsFidOpenState *fs)
+{
+ return false;
+}
+
FileOperations synth_ops = {
.init = synth_init,
.lstat = synth_lstat,
@@ -650,4 +669,7 @@ FileOperations synth_ops = {
.name_to_path = synth_name_to_path,
.renameat = synth_renameat,
.unlinkat = synth_unlinkat,
+ .has_valid_file_handle = synth_has_valid_file_handle,
+ .ftruncate = synth_ftruncate,
+ .futimens = synth_futimens,
};
diff --git a/hw/9pfs/9p-util-generic.c b/hw/9pfs/9p-util-generic.c
new file mode 100644
index 0000000..4c1e9c8
--- /dev/null
+++ b/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) */
+ );
+}
diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
index 51c94b0..a1924fe 100644
--- a/hw/9pfs/9p-util.h
+++ b/hw/9pfs/9p-util.h
@@ -103,6 +103,7 @@ static inline int errno_to_dotl(int err) {
#define qemu_renameat renameat
#define qemu_utimensat utimensat
#define qemu_unlinkat unlinkat
+#define qemu_futimens futimens
static inline void close_preserve_errno(int fd)
{
@@ -177,20 +178,27 @@ again:
return -1;
}
- if (close_if_special_file(fd) < 0) {
- return -1;
- }
-
- serrno = errno;
- /* O_NONBLOCK was only needed to open the file. Let's drop it. We don't
- * do that with O_PATH since fcntl(F_SETFL) isn't supported, and openat()
- * ignored it anyway.
- */
+ /* Only if O_PATH is not set ... */
if (!(flags & O_PATH_9P_UTIL)) {
+ /*
+ * Prevent I/O on special files (device files, etc.) on host side,
+ * however it is safe and required to allow opening them with O_PATH,
+ * as this is limited to (required) path based operations only.
+ */
+ if (close_if_special_file(fd) < 0) {
+ return -1;
+ }
+
+ serrno = errno;
+ /*
+ * O_NONBLOCK was only needed to open the file. Let's drop it. We don't
+ * do that with O_PATH since fcntl(F_SETFL) isn't supported, and
+ * openat() ignored it anyway.
+ */
ret = fcntl(fd, F_SETFL, flags);
assert(!ret);
+ errno = serrno;
}
- errno = serrno;
return fd;
}
@@ -260,4 +268,10 @@ int pthread_fchdir_np(int fd) __attribute__((weak_import));
#endif
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
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index af636cf..8b001b9 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -434,16 +434,24 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu)
V9fsFidState *f;
GHashTableIter iter;
gpointer fid;
+ int err;
+ int nclosed = 0;
+
+ /* prevent multiple coroutines running this function simultaniously */
+ if (s->reclaiming) {
+ return;
+ }
+ s->reclaiming = true;
g_hash_table_iter_init(&iter, s->fids);
QSLIST_HEAD(, V9fsFidState) reclaim_list =
QSLIST_HEAD_INITIALIZER(reclaim_list);
+ /* Pick FIDs to be closed, collect them on reclaim_list. */
while (g_hash_table_iter_next(&iter, &fid, (gpointer *) &f)) {
/*
- * Unlink fids cannot be reclaimed. Check
- * for them and skip them. Also skip fids
+ * Unlinked fids cannot be reclaimed, skip those, and also skip fids
* currently being operated on.
*/
if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
@@ -493,23 +501,42 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu)
}
}
/*
- * Now close the fid in reclaim list. Free them if they
- * are already clunked.
+ * Close the picked FIDs altogether on a background I/O driver thread. Do
+ * this all at once to keep latency (i.e. amount of thread hops between main
+ * thread <-> fs driver background thread) as low as possible.
*/
+ v9fs_co_run_in_worker({
+ QSLIST_FOREACH(f, &reclaim_list, reclaim_next) {
+ err = (f->fid_type == P9_FID_DIR) ?
+ s->ops->closedir(&s->ctx, &f->fs_reclaim) :
+ s->ops->close(&s->ctx, &f->fs_reclaim);
+
+ /* 'man 2 close' suggests to ignore close() errors except of EBADF */
+ if (unlikely(err && errno == EBADF)) {
+ /*
+ * unexpected case as FIDs were picked above by having a valid
+ * file descriptor
+ */
+ error_report("9pfs: v9fs_reclaim_fd() WARNING: close() failed with EBADF");
+ } else {
+ /* total_open_fd must only be mutated on main thread */
+ nclosed++;
+ }
+ }
+ });
+ total_open_fd -= nclosed;
+ /* Free the closed FIDs. */
while (!QSLIST_EMPTY(&reclaim_list)) {
f = QSLIST_FIRST(&reclaim_list);
QSLIST_REMOVE(&reclaim_list, f, V9fsFidState, reclaim_next);
- if (f->fid_type == P9_FID_FILE) {
- v9fs_co_close(pdu, &f->fs_reclaim);
- } else if (f->fid_type == P9_FID_DIR) {
- v9fs_co_closedir(pdu, &f->fs_reclaim);
- }
/*
* Now drop the fid reference, free it
* if clunked.
*/
put_fid(pdu, f);
}
+
+ s->reclaiming = false;
}
/*
@@ -1574,6 +1601,11 @@ out_nofid:
pdu_complete(pdu, err);
}
+static bool fid_has_valid_file_handle(V9fsState *s, V9fsFidState *fidp)
+{
+ return s->ops->has_valid_file_handle(fidp->fid_type, &fidp->fs);
+}
+
static void coroutine_fn v9fs_getattr(void *opaque)
{
int32_t fid;
@@ -1596,11 +1628,11 @@ static void coroutine_fn v9fs_getattr(void *opaque)
retval = -ENOENT;
goto out_nofid;
}
- /*
- * Currently we only support BASIC fields in stat, so there is no
- * need to look at request_mask.
- */
- retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
+ if (fid_has_valid_file_handle(pdu->s, fidp)) {
+ retval = v9fs_co_fstat(pdu, fidp, &stbuf);
+ } else {
+ retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
+ }
if (retval < 0) {
goto out;
}
@@ -1703,7 +1735,11 @@ static void coroutine_fn v9fs_setattr(void *opaque)
} else {
times[1].tv_nsec = UTIME_OMIT;
}
- err = v9fs_co_utimensat(pdu, &fidp->path, times);
+ if (fid_has_valid_file_handle(pdu->s, fidp)) {
+ err = v9fs_co_futimens(pdu, fidp, times);
+ } else {
+ err = v9fs_co_utimensat(pdu, &fidp->path, times);
+ }
if (err < 0) {
goto out;
}
@@ -1728,7 +1764,11 @@ static void coroutine_fn v9fs_setattr(void *opaque)
}
}
if (v9iattr.valid & (P9_ATTR_SIZE)) {
- err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
+ if (fid_has_valid_file_handle(pdu->s, fidp)) {
+ err = v9fs_co_ftruncate(pdu, fidp, v9iattr.size);
+ } else {
+ err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
+ }
if (err < 0) {
goto out;
}
@@ -1772,6 +1812,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;
}
+/*
+ * 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)
{
int name_idx, nwalked;
@@ -1785,6 +1840,7 @@ static void coroutine_fn v9fs_walk(void *opaque)
size_t offset = 7;
int32_t fid, newfid;
P9ARRAY_REF(V9fsString) wnames = NULL;
+ g_autofree char *trace_wnames = NULL;
V9fsFidState *fidp;
V9fsFidState *newfidp = NULL;
V9fsPDU *pdu = opaque;
@@ -1798,11 +1854,9 @@ static void coroutine_fn v9fs_walk(void *opaque)
}
offset += err;
- trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
-
if (nwnames > P9_MAXWELEM) {
err = -EINVAL;
- goto out_nofid;
+ goto out_nofid_nownames;
}
if (nwnames) {
P9ARRAY_NEW(V9fsString, wnames, nwnames);
@@ -1812,15 +1866,23 @@ static void coroutine_fn v9fs_walk(void *opaque)
for (i = 0; i < nwnames; i++) {
err = pdu_unmarshal(pdu, offset, "s", &wnames[i]);
if (err < 0) {
- goto out_nofid;
+ goto out_nofid_nownames;
}
if (name_is_illegal(wnames[i].data)) {
err = -ENOENT;
- goto out_nofid;
+ goto out_nofid_nownames;
}
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);
if (fidp == NULL) {
err = -ENOENT;
@@ -1955,7 +2017,11 @@ out:
}
v9fs_path_free(&dpath);
v9fs_path_free(&path);
+ goto out_pdu_complete;
+out_nofid_nownames:
+ trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames, "<?>");
out_nofid:
+out_pdu_complete:
pdu_complete(pdu, err);
}
@@ -1980,6 +2046,7 @@ static void coroutine_fn v9fs_open(void *opaque)
V9fsFidState *fidp;
V9fsPDU *pdu = opaque;
V9fsState *s = pdu->s;
+ g_autofree char *trace_oflags = NULL;
if (s->proto_version == V9FS_PROTO_2000L) {
err = pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
@@ -1991,7 +2058,13 @@ static void coroutine_fn v9fs_open(void *opaque)
if (err < 0) {
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);
if (fidp == NULL) {
@@ -2587,6 +2660,11 @@ static void coroutine_fn v9fs_readdir(void *opaque)
retval = -EINVAL;
goto out_nofid;
}
+ if (fidp->fid_type != P9_FID_DIR) {
+ warn_report_once("9p: bad client: T_readdir on non-directory stream");
+ retval = -ENOTDIR;
+ goto out;
+ }
if (!fidp->fs.dir.stream) {
retval = -EINVAL;
goto out;
@@ -4284,6 +4362,8 @@ int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t,
s->ctx.fst = &fse->fst;
fsdev_throttle_init(s->ctx.fst);
+ s->reclaiming = false;
+
rc = 0;
out:
if (rc) {
diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
index a6f59ab..259ad32 100644
--- a/hw/9pfs/9p.h
+++ b/hw/9pfs/9p.h
@@ -280,7 +280,6 @@ struct V9fsFidState {
uid_t uid;
int ref;
bool clunked;
- QSIMPLEQ_ENTRY(V9fsFidState) next;
QSLIST_ENTRY(V9fsFidState) reclaim_next;
};
@@ -363,6 +362,7 @@ struct V9fsState {
uint64_t qp_ndevices; /* Amount of entries in qpd_table. */
uint16_t qp_affix_next;
uint64_t qp_fullpath_next;
+ bool reclaiming;
};
/* 9p2000.L open flags */
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index 2068a47..bce7dd9 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -20,6 +20,7 @@
#include "fsdev/qemu-fsdev.h"
#include "qemu/thread.h"
#include "qemu/main-loop.h"
+#include "qemu/error-report.h"
#include "coth.h"
#include "9p-xattr.h"
#include "9p-util.h"
@@ -353,7 +354,11 @@ int coroutine_fn v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState *fs)
err = -errno;
}
});
- if (!err) {
+ /* 'man 2 close' suggests to ignore close() errors except of EBADF */
+ if (unlikely(err && errno == EBADF)) {
+ /* unexpected case as we should have checked for a valid file handle */
+ error_report("9pfs: WARNING: v9fs_co_closedir() failed with EBADF");
+ } else {
total_open_fd--;
}
return err;
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 71174c3..6e775c8 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -20,6 +20,7 @@
#include "fsdev/qemu-fsdev.h"
#include "qemu/thread.h"
#include "qemu/main-loop.h"
+#include "qemu/error-report.h"
#include "coth.h"
int coroutine_fn v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode,
@@ -197,7 +198,11 @@ int coroutine_fn v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs)
err = -errno;
}
});
- if (!err) {
+ /* 'man 2 close' suggests to ignore close() errors except of EBADF */
+ if (unlikely(err && errno == EBADF)) {
+ /* unexpected case as we should have checked for a valid file handle */
+ error_report("9pfs: WARNING: v9fs_co_close() failed with EBADF");
+ } else {
total_open_fd--;
}
return err;
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 67e3ae5..12fa8c9 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -139,6 +139,25 @@ int coroutine_fn v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path,
return err;
}
+int coroutine_fn v9fs_co_futimens(V9fsPDU *pdu, V9fsFidState *fidp,
+ struct timespec times[2])
+{
+ int err;
+ V9fsState *s = pdu->s;
+
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_co_run_in_worker(
+ {
+ err = s->ops->futimens(&s->ctx, fidp->fid_type, &fidp->fs, times);
+ if (err < 0) {
+ err = -errno;
+ }
+ });
+ return err;
+}
+
int coroutine_fn v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid,
gid_t gid)
{
@@ -184,6 +203,24 @@ int coroutine_fn v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
return err;
}
+int coroutine_fn v9fs_co_ftruncate(V9fsPDU *pdu, V9fsFidState *fidp, off_t size)
+{
+ int err;
+ V9fsState *s = pdu->s;
+
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_co_run_in_worker(
+ {
+ err = s->ops->ftruncate(&s->ctx, fidp->fid_type, &fidp->fs, size);
+ if (err < 0) {
+ err = -errno;
+ }
+ });
+ return err;
+}
+
int coroutine_fn v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp,
V9fsString *name, uid_t uid, gid_t gid,
dev_t dev, mode_t mode, struct stat *stbuf)
diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h
index 2c54249..7906fa7 100644
--- a/hw/9pfs/coth.h
+++ b/hw/9pfs/coth.h
@@ -71,8 +71,12 @@ int coroutine_fn v9fs_co_statfs(V9fsPDU *, V9fsPath *, struct statfs *);
int coroutine_fn v9fs_co_lstat(V9fsPDU *, V9fsPath *, struct stat *);
int coroutine_fn v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t);
int coroutine_fn v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]);
+int coroutine_fn v9fs_co_futimens(V9fsPDU *pdu, V9fsFidState *fidp,
+ struct timespec times[2]);
int coroutine_fn v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t);
int coroutine_fn v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t);
+int coroutine_fn v9fs_co_ftruncate(V9fsPDU *pdu, V9fsFidState *fidp,
+ off_t size);
int coroutine_fn v9fs_co_llistxattr(V9fsPDU *, V9fsPath *, void *, size_t);
int coroutine_fn v9fs_co_lgetxattr(V9fsPDU *, V9fsPath *,
V9fsString *, void *, size_t);
diff --git a/hw/9pfs/meson.build b/hw/9pfs/meson.build
index f1b62fa..d35d4f4 100644
--- a/hw/9pfs/meson.build
+++ b/hw/9pfs/meson.build
@@ -2,8 +2,8 @@ fs_ss = ss.source_set()
fs_ss.add(files(
'9p-local.c',
'9p-posix-acl.c',
- '9p-proxy.c',
'9p-synth.c',
+ '9p-util-generic.c',
'9p-xattr-user.c',
'9p-xattr.c',
'9p.c',
diff --git a/hw/9pfs/trace-events b/hw/9pfs/trace-events
index a12e55c..0e0fc37 100644
--- a/hw/9pfs/trace-events
+++ b/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_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(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_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_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"
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index efa41cf..81b91e4 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -26,7 +26,7 @@
#include "hw/virtio/virtio-access.h"
#include "qemu/iov.h"
#include "qemu/module.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
static void virtio_9p_push_and_notify(V9fsPDU *pdu)
{
@@ -243,13 +243,12 @@ static const VMStateDescription vmstate_virtio_9p = {
},
};
-static Property virtio_9p_properties[] = {
+static const Property virtio_9p_properties[] = {
DEFINE_PROP_STRING("mount_tag", V9fsVirtioState, state.fsconf.tag),
DEFINE_PROP_STRING("fsdev", V9fsVirtioState, state.fsconf.fsdev_id),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_9p_class_init(ObjectClass *klass, void *data)
+static void virtio_9p_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);