From 416488360b334083743b08d94f7f76c526db0042 Mon Sep 17 00:00:00 2001 From: Michael Roitzsch Date: Mon, 22 Mar 2021 21:55:55 +0100 Subject: [PATCH] qemu: add 9p virtfs support on Darwin --- .../virtualization/qemu/9p-darwin.patch | 1059 +++++++++++++++++ .../virtualization/qemu/default.nix | 5 +- 2 files changed, 1062 insertions(+), 2 deletions(-) create mode 100644 pkgs/applications/virtualization/qemu/9p-darwin.patch diff --git a/pkgs/applications/virtualization/qemu/9p-darwin.patch b/pkgs/applications/virtualization/qemu/9p-darwin.patch new file mode 100644 index 0000000000000..d745b546dc5da --- /dev/null +++ b/pkgs/applications/virtualization/qemu/9p-darwin.patch @@ -0,0 +1,1059 @@ +From 19032cc9de8c734c6735c3f304327cc05a88dd0c Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Sat, 16 Jun 2018 20:56:45 -0400 +Subject: [PATCH 01/11] 9p: linux: Fix a couple Linux assumptions + + - Guard Linux only headers. + - Add qemu/statfs.h header to abstract over the which + headers are needed for struct statfs + - Define `ENOATTR` only if not only defined + (it's defined in system headers on Darwin). + +Signed-off-by: Keno Fischer +--- + fsdev/file-op-9p.h | 2 +- + hw/9pfs/9p-local.c | 2 ++ + hw/9pfs/9p.c | 2 +- + include/qemu/statfs.h | 19 +++++++++++++++++++ + include/qemu/xattr.h | 4 +++- + 5 files changed, 26 insertions(+), 3 deletions(-) + create mode 100644 include/qemu/statfs.h + +diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h +index 42f677c..d9d058b 100644 +--- a/fsdev/file-op-9p.h ++++ b/fsdev/file-op-9p.h +@@ -16,7 +16,7 @@ + + #include + #include +-#include ++#include "qemu/statfs.h" + #include "qemu-fsdev-throttle.h" + + #define SM_LOCAL_MODE_BITS 0600 +diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c +index af52c1d..452a0d6 100644 +--- a/hw/9pfs/9p-local.c ++++ b/hw/9pfs/9p-local.c +@@ -27,10 +27,12 @@ + #include "qemu/error-report.h" + #include "qemu/option.h" + #include ++#ifdef CONFIG_LINUX + #include + #ifdef CONFIG_LINUX_MAGIC_H + #include + #endif ++#endif + #include + + #ifndef XFS_SUPER_MAGIC +diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c +index 134806d..8932da6 100644 +--- a/hw/9pfs/9p.c ++++ b/hw/9pfs/9p.c +@@ -27,7 +27,7 @@ + #include "migration/blocker.h" + #include "qemu/xxhash.h" + #include +-#include ++#include + + int open_fd_hw; + int total_open_fd; +diff --git a/include/qemu/statfs.h b/include/qemu/statfs.h +new file mode 100644 +index 0000000..dde289f +--- /dev/null ++++ b/include/qemu/statfs.h +@@ -0,0 +1,19 @@ ++/* ++ * Host statfs header abstraction ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2, or any ++ * later version. See the COPYING file in the top-level directory. ++ * ++ */ ++#ifndef QEMU_STATFS_H ++#define QEMU_STATFS_H ++ ++#ifdef CONFIG_LINUX ++# include ++#endif ++#ifdef CONFIG_DARWIN ++# include ++# include ++#endif ++ ++#endif +diff --git a/include/qemu/xattr.h b/include/qemu/xattr.h +index a83fe8e..f1d0f7b 100644 +--- a/include/qemu/xattr.h ++++ b/include/qemu/xattr.h +@@ -22,7 +22,9 @@ + #ifdef CONFIG_LIBATTR + # include + #else +-# define ENOATTR ENODATA ++# if !defined(ENOATTR) ++# define ENOATTR ENODATA ++# endif + # include + #endif + +-- +2.30.1 (Apple Git-130) + +From 92bbaad998214154caef3c23eafa90484832c02f Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Sat, 16 Jun 2018 20:56:46 -0400 +Subject: [PATCH 02/11] 9p: Rename 9p-util -> 9p-util-linux + +The current file only has the Linux versions of these functions. +Rename the file accordingly and update the Makefile to only build +it on Linux. A Darwin version of these will follow later in the +series. + +Signed-off-by: Keno Fischer +Signed-off-by: Michael Roitzsch +--- + hw/9pfs/{9p-util.c => 9p-util-linux.c} | 2 +- + hw/9pfs/meson.build | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + rename hw/9pfs/{9p-util.c => 9p-util-linux.c} (97%) + +diff --git a/hw/9pfs/9p-util.c b/hw/9pfs/9p-util-linux.c +similarity index 97% +rename from hw/9pfs/9p-util.c +rename to hw/9pfs/9p-util-linux.c +index 614b7fc..defa3a4 100644 +--- a/hw/9pfs/9p-util.c ++++ b/hw/9pfs/9p-util-linux.c +@@ -1,5 +1,5 @@ + /* +- * 9p utilities ++ * 9p utilities (Linux Implementation) + * + * Copyright IBM, Corp. 2017 + * +diff --git a/hw/9pfs/meson.build b/hw/9pfs/meson.build +index 99be5d9..1b28e70 100644 +--- a/hw/9pfs/meson.build ++++ b/hw/9pfs/meson.build +@@ -4,7 +4,6 @@ fs_ss.add(files( + '9p-posix-acl.c', + '9p-proxy.c', + '9p-synth.c', +- '9p-util.c', + '9p-xattr-user.c', + '9p-xattr.c', + '9p.c', +@@ -14,6 +13,7 @@ fs_ss.add(files( + 'coth.c', + 'coxattr.c', + )) ++fs_ss.add(when: 'CONFIG_LINUX', if_true: files('9p-util-linux.c')) + fs_ss.add(when: 'CONFIG_XEN', if_true: files('xen-9p-backend.c')) + softmmu_ss.add_all(when: 'CONFIG_FSDEV_9P', if_true: fs_ss) + +-- +2.30.1 (Apple Git-130) + +From 9e041f6a1ebaeb322a32ae606f21f8082bc664e4 Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Sat, 16 Jun 2018 20:56:47 -0400 +Subject: [PATCH 03/11] 9p: darwin: Handle struct stat(fs) differences + +Signed-off-by: Keno Fischer +--- + hw/9pfs/9p-proxy.c | 17 ++++++++++++++--- + hw/9pfs/9p-synth.c | 2 ++ + hw/9pfs/9p.c | 16 ++++++++++++++-- + 3 files changed, 30 insertions(+), 5 deletions(-) + +diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c +index 4aa4e0a..9db07df 100644 +--- a/hw/9pfs/9p-proxy.c ++++ b/hw/9pfs/9p-proxy.c +@@ -118,10 +118,15 @@ static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs) + stfs->f_bavail = prstfs->f_bavail; + stfs->f_files = prstfs->f_files; + stfs->f_ffree = prstfs->f_ffree; ++#ifdef CONFIG_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 */ +@@ -138,12 +143,18 @@ static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat) + stbuf->st_size = prstat->st_size; + stbuf->st_blksize = prstat->st_blksize; + stbuf->st_blocks = prstat->st_blocks; +- stbuf->st_atim.tv_sec = prstat->st_atim_sec; +- stbuf->st_atim.tv_nsec = prstat->st_atim_nsec; ++ stbuf->st_atime = prstat->st_atim_sec; + stbuf->st_mtime = prstat->st_mtim_sec; +- stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec; + stbuf->st_ctime = prstat->st_ctim_sec; ++#ifdef CONFIG_DARWIN ++ 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_nsec = prstat->st_atim_nsec; ++ stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec; + stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec; ++#endif + } + + /* +diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c +index 473ef91..6318be8 100644 +--- a/hw/9pfs/9p-synth.c ++++ b/hw/9pfs/9p-synth.c +@@ -422,7 +422,9 @@ static int synth_statfs(FsContext *s, V9fsPath *fs_path, + stbuf->f_bsize = 512; + stbuf->f_blocks = 0; + stbuf->f_files = synth_node_count; ++#ifndef CONFIG_DARWIN + stbuf->f_namelen = NAME_MAX; ++#endif + return 0; + } + +diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c +index 8932da6..c40bfd5 100644 +--- a/hw/9pfs/9p.c ++++ b/hw/9pfs/9p.c +@@ -1288,11 +1288,17 @@ static int stat_to_v9stat_dotl(V9fsPDU *pdu, const struct stat *stbuf, + v9lstat->st_blksize = stbuf->st_blksize; + v9lstat->st_blocks = stbuf->st_blocks; + v9lstat->st_atime_sec = stbuf->st_atime; +- v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec; + v9lstat->st_mtime_sec = stbuf->st_mtime; +- v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec; + v9lstat->st_ctime_sec = stbuf->st_ctime; ++#ifdef CONFIG_DARWIN ++ v9lstat->st_atime_nsec = stbuf->st_atimespec.tv_nsec; ++ v9lstat->st_mtime_nsec = stbuf->st_mtimespec.tv_nsec; ++ v9lstat->st_ctime_nsec = stbuf->st_ctimespec.tv_nsec; ++#else ++ v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec; ++ v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec; + v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec; ++#endif + /* Currently we only support BASIC fields in stat */ + v9lstat->st_result_mask = P9_STATS_BASIC; + +@@ -3456,9 +3462,15 @@ static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf) + f_bavail = stbuf->f_bavail / bsize_factor; + f_files = stbuf->f_files; + f_ffree = stbuf->f_ffree; ++#ifdef CONFIG_DARWIN ++ fsid_val = (unsigned int)stbuf->f_fsid.val[0] | ++ (unsigned long long)stbuf->f_fsid.val[1] << 32; ++ f_namelen = MAXNAMLEN; ++#else + fsid_val = (unsigned int) stbuf->f_fsid.__val[0] | + (unsigned long long)stbuf->f_fsid.__val[1] << 32; + f_namelen = stbuf->f_namelen; ++#endif + + return pdu_marshal(pdu, offset, "ddqqqqqqd", + f_type, f_bsize, f_blocks, f_bfree, +-- +2.30.1 (Apple Git-130) + +From e0391f158fd6f98306ccfc95c9d737860b896c96 Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Sat, 16 Jun 2018 20:56:48 -0400 +Subject: [PATCH 04/11] 9p: darwin: Handle struct dirent differences + +On darwin d_seekoff exists, but is optional and does not seem to +be commonly used by file systems. Use `telldir` instead to obtain +the seek offset. + +Signed-off-by: Keno Fischer +Signed-off-by: Michael Roitzsch +--- + hw/9pfs/9p-synth.c | 2 ++ + hw/9pfs/9p.c | 33 +++++++++++++++++++++++++++++++-- + hw/9pfs/codir.c | 4 ++++ + 3 files changed, 37 insertions(+), 2 deletions(-) + +diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c +index 6318be8..d538fd4 100644 +--- a/hw/9pfs/9p-synth.c ++++ b/hw/9pfs/9p-synth.c +@@ -217,7 +217,9 @@ static void synth_direntry(V9fsSynthNode *node, + { + strcpy(entry->d_name, node->name); + entry->d_ino = node->attr->inode; ++#ifndef CONFIG_DARWIN + entry->d_off = off + 1; ++#endif + } + + static struct dirent *synth_get_dentry(V9fsSynthNode *dir, +diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c +index c40bfd5..3bad4e6 100644 +--- a/hw/9pfs/9p.c ++++ b/hw/9pfs/9p.c +@@ -2155,6 +2155,25 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, + return offset; + } + ++/** ++ * Get the seek offset of a dirent. If not available from the structure itself, ++ * obtain it by calling telldir. ++ */ ++static int v9fs_dent_telldir(V9fsPDU *pdu, V9fsFidState *fidp, ++ struct dirent *dent) ++{ ++#ifdef CONFIG_DARWIN ++ /* ++ * Darwin has d_seekoff, which appears to function similarly to d_off. ++ * However, it does not appear to be supported on all file systems, ++ * so use telldir for correctness. ++ */ ++ return telldir(fidp->fs.dir.stream); ++#else ++ return dent->d_off; ++#endif ++} ++ + static int coroutine_fn v9fs_do_readdir_with_stat(V9fsPDU *pdu, + V9fsFidState *fidp, + uint32_t max_count) +@@ -2218,7 +2237,11 @@ static int coroutine_fn v9fs_do_readdir_with_stat(V9fsPDU *pdu, + count += len; + v9fs_stat_free(&v9stat); + v9fs_path_free(&path); +- saved_dir_pos = dent->d_off; ++ saved_dir_pos = v9fs_dent_telldir(pdu, fidp, dent); ++ if (saved_dir_pos < 0) { ++ err = saved_dir_pos; ++ break; ++ } + } + + v9fs_readdir_unlock(&fidp->fs.dir); +@@ -2357,6 +2380,7 @@ static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, + V9fsString name; + int len, err = 0; + int32_t count = 0; ++ off_t off; + struct dirent *dent; + struct stat *st; + struct V9fsDirEnt *entries = NULL; +@@ -2417,12 +2441,17 @@ static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, + qid.version = 0; + } + ++ off = v9fs_dent_telldir(pdu, fidp, dent); ++ if (off < 0) { ++ err = off; ++ break; ++ } + v9fs_string_init(&name); + v9fs_string_sprintf(&name, "%s", dent->d_name); + + /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */ + len = pdu_marshal(pdu, 11 + count, "Qqbs", +- &qid, dent->d_off, ++ &qid, off, + dent->d_type, &name); + + v9fs_string_free(&name); +diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c +index 1f70a58..3f0e753 100644 +--- a/hw/9pfs/codir.c ++++ b/hw/9pfs/codir.c +@@ -162,7 +162,11 @@ static int do_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp, + } + + size += len; ++#ifdef CONFIG_DARWIN ++ saved_dir_pos = telldir(fidp->fs.dir.stream); ++#else + saved_dir_pos = dent->d_off; ++#endif + } + + /* restore (last) saved position */ +-- +2.30.1 (Apple Git-130) + +From e3013be65bd0d34041bbc1543b0dd058fcee5069 Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Sat, 16 Jun 2018 20:56:50 -0400 +Subject: [PATCH 05/11] 9p: darwin: Ignore O_{NOATIME, DIRECT} + +Darwin doesn't have either of these flags. Darwin does have +F_NOCACHE, which is similar to O_DIRECT, but has different +enough semantics that other projects don't generally map +them automatically. In any case, we don't support O_DIRECT +on Linux at the moment either. + +Signed-off-by: Keno Fischer +Reviewed-by: Greg Kurz +Signed-off-by: Michael Roitzsch +--- + hw/9pfs/9p-util.h | 2 ++ + hw/9pfs/9p.c | 11 ++++++++++- + 2 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h +index 546f46d..627baeb 100644 +--- a/hw/9pfs/9p-util.h ++++ b/hw/9pfs/9p-util.h +@@ -41,6 +41,7 @@ again: + fd = openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK, + mode); + if (fd == -1) { ++#ifndef CONFIG_DARWIN + if (errno == EPERM && (flags & O_NOATIME)) { + /* + * The client passed O_NOATIME but we lack permissions to honor it. +@@ -53,6 +54,7 @@ again: + flags &= ~O_NOATIME; + goto again; + } ++#endif + return -1; + } + +diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c +index 3bad4e6..c1d8bc9 100644 +--- a/hw/9pfs/9p.c ++++ b/hw/9pfs/9p.c +@@ -126,11 +126,18 @@ static int dotl_to_open_flags(int flags) + { P9_DOTL_NONBLOCK, O_NONBLOCK } , + { P9_DOTL_DSYNC, O_DSYNC }, + { P9_DOTL_FASYNC, FASYNC }, ++#ifndef CONFIG_DARWIN ++ { P9_DOTL_NOATIME, O_NOATIME }, ++ /* On Darwin, we could map to F_NOCACHE, which is ++ similar, but doesn't quite have the same ++ semantics. However, we don't support O_DIRECT ++ even on linux at the moment, so we just ignore ++ it here. */ + { P9_DOTL_DIRECT, O_DIRECT }, ++#endif + { 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 }, + }; + +@@ -159,10 +166,12 @@ static int get_dotl_openflags(V9fsState *s, int oflags) + */ + flags = dotl_to_open_flags(oflags); + flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT); ++#ifndef CONFIG_DARWIN + /* + * Ignore direct disk access hint until the server supports it. + */ + flags &= ~O_DIRECT; ++#endif + return flags; + } + +-- +2.30.1 (Apple Git-130) + +From c65566e3a70a51bb39d33fcd94966b21b63501f5 Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Sat, 16 Jun 2018 20:56:51 -0400 +Subject: [PATCH 06/11] 9p: darwin: Provide a compatibility definition for + XATTR_SIZE_MAX + +Signed-off-by: Keno Fischer +--- + hw/9pfs/9p.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c +index c1d8bc9..0fe5976 100644 +--- a/hw/9pfs/9p.c ++++ b/hw/9pfs/9p.c +@@ -3878,6 +3878,13 @@ out_nofid: + v9fs_string_free(&name); + } + ++#if defined(CONFIG_DARWIN) && !defined(XATTR_SIZE_MAX) ++/* Darwin doesn't seem to define a maximum xattr size in its user ++ space header, but looking at the kernel source, HFS supports ++ up to INT32_MAX, so use that as the maximum. ++*/ ++#define XATTR_SIZE_MAX INT32_MAX ++#endif + static void coroutine_fn v9fs_xattrcreate(void *opaque) + { + int flags, rflags = 0; +-- +2.30.1 (Apple Git-130) + +From edfa6e204ac905fd00e5cba052a6c6f3d36faf4e Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Sat, 16 Jun 2018 20:56:52 -0400 +Subject: [PATCH 07/11] 9p: darwin: *xattr_nofollow implementations + +This implements the darwin equivalent of the functions that were +moved to 9p-util(-linux) earlier in this series in the new +9p-util-darwin file. + +Signed-off-by: Keno Fischer +Signed-off-by: Michael Roitzsch +--- + hw/9pfs/9p-util-darwin.c | 64 ++++++++++++++++++++++++++++++++++++++++ + hw/9pfs/meson.build | 1 + + 2 files changed, 65 insertions(+) + create mode 100644 hw/9pfs/9p-util-darwin.c + +diff --git a/hw/9pfs/9p-util-darwin.c b/hw/9pfs/9p-util-darwin.c +new file mode 100644 +index 0000000..cdb4c9e +--- /dev/null ++++ b/hw/9pfs/9p-util-darwin.c +@@ -0,0 +1,64 @@ ++/* ++ * 9p utilities (Darwin Implementation) ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/xattr.h" ++#include "9p-util.h" ++ ++ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name, ++ void *value, size_t size) ++{ ++ int ret; ++ int fd = openat_file(dirfd, filename, ++ O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0); ++ if (fd == -1) { ++ return -1; ++ } ++ ret = fgetxattr(fd, name, value, size, 0, 0); ++ close_preserve_errno(fd); ++ return ret; ++} ++ ++ssize_t flistxattrat_nofollow(int dirfd, const char *filename, ++ char *list, size_t size) ++{ ++ int ret; ++ int fd = openat_file(dirfd, filename, ++ O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0); ++ if (fd == -1) { ++ return -1; ++ } ++ ret = flistxattr(fd, list, size, 0); ++ close_preserve_errno(fd); ++ return ret; ++} ++ ++ssize_t fremovexattrat_nofollow(int dirfd, const char *filename, ++ const char *name) ++{ ++ int ret; ++ int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0); ++ if (fd == -1) { ++ return -1; ++ } ++ ret = fremovexattr(fd, name, 0); ++ close_preserve_errno(fd); ++ return ret; ++} ++ ++int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name, ++ void *value, size_t size, int flags) ++{ ++ int ret; ++ int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0); ++ if (fd == -1) { ++ return -1; ++ } ++ ret = fsetxattr(fd, name, value, size, 0, flags); ++ close_preserve_errno(fd); ++ return ret; ++} +diff --git a/hw/9pfs/meson.build b/hw/9pfs/meson.build +index 1b28e70..12443b6 100644 +--- a/hw/9pfs/meson.build ++++ b/hw/9pfs/meson.build +@@ -14,6 +14,7 @@ fs_ss.add(files( + 'coxattr.c', + )) + fs_ss.add(when: 'CONFIG_LINUX', if_true: files('9p-util-linux.c')) ++fs_ss.add(when: 'CONFIG_DARWIN', if_true: files('9p-util-darwin.c')) + fs_ss.add(when: 'CONFIG_XEN', if_true: files('xen-9p-backend.c')) + softmmu_ss.add_all(when: 'CONFIG_FSDEV_9P', if_true: fs_ss) + +-- +2.30.1 (Apple Git-130) + +From 9b5abaa7e2710c0d05b4d33af4913f1411435e8d Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Sat, 16 Jun 2018 20:56:53 -0400 +Subject: [PATCH 08/11] 9p: darwin: Compatibility for f/l*xattr + +On darwin `fgetxattr` takes two extra optional arguments, +and the l* variants are not defined (in favor of an extra +flag to the regular variants. + +Signed-off-by: Keno Fischer +Reviewed-by: Greg Kurz +--- + hw/9pfs/9p-local.c | 12 ++++++++---- + hw/9pfs/9p-util.h | 17 +++++++++++++++++ + 2 files changed, 25 insertions(+), 4 deletions(-) + +diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c +index 452a0d6..8f7e198 100644 +--- a/hw/9pfs/9p-local.c ++++ b/hw/9pfs/9p-local.c +@@ -776,16 +776,20 @@ static int local_fstat(FsContext *fs_ctx, int fid_type, + mode_t tmp_mode; + dev_t tmp_dev; + +- if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { ++ if (qemu_fgetxattr(fd, "user.virtfs.uid", ++ &tmp_uid, sizeof(uid_t)) > 0) { + stbuf->st_uid = le32_to_cpu(tmp_uid); + } +- if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { ++ if (qemu_fgetxattr(fd, "user.virtfs.gid", ++ &tmp_gid, sizeof(gid_t)) > 0) { + stbuf->st_gid = le32_to_cpu(tmp_gid); + } +- if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) { ++ if (qemu_fgetxattr(fd, "user.virtfs.mode", ++ &tmp_mode, sizeof(mode_t)) > 0) { + stbuf->st_mode = le32_to_cpu(tmp_mode); + } +- if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { ++ if (qemu_fgetxattr(fd, "user.virtfs.rdev", ++ &tmp_dev, sizeof(dev_t)) > 0) { + stbuf->st_rdev = le64_to_cpu(tmp_dev); + } + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { +diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h +index 627baeb..38ef8b2 100644 +--- a/hw/9pfs/9p-util.h ++++ b/hw/9pfs/9p-util.h +@@ -19,6 +19,23 @@ + #define O_PATH_9P_UTIL 0 + #endif + ++#ifdef CONFIG_DARWIN ++#define qemu_fgetxattr(...) fgetxattr(__VA_ARGS__, 0, 0) ++#define qemu_lgetxattr(...) getxattr(__VA_ARGS__, 0, XATTR_NOFOLLOW) ++#define qemu_llistxattr(...) listxattr(__VA_ARGS__, XATTR_NOFOLLOW) ++#define qemu_lremovexattr(...) removexattr(__VA_ARGS__, XATTR_NOFOLLOW) ++static inline int qemu_lsetxattr(const char *path, const char *name, ++ const void *value, size_t size, int flags) { ++ return setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW); ++} ++#else ++#define qemu_fgetxattr fgetxattr ++#define qemu_lgetxattr lgetxattr ++#define qemu_llistxattr llistxattr ++#define qemu_lremovexattr lremovexattr ++#define qemu_lsetxattr lsetxattr ++#endif ++ + static inline void close_preserve_errno(int fd) + { + int serrno = errno; +-- +2.30.1 (Apple Git-130) + +From 5189fbeea0d239e51b397f4e87a3c07454743bf6 Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Sat, 16 Jun 2018 20:56:54 -0400 +Subject: [PATCH 09/11] 9p: darwin: Provide a fallback implementation for + utimensat + +This function is new in Mac OS 10.13. Provide a fallback implementation +when building against older SDKs. The complication in the definition comes +having to separately handle the used SDK version and the target OS version. + +- If the SDK version is too low (__MAC_10_13 not defined), utimensat is not + defined in the header, so we must not try to use it (doing so would error). +- Otherwise, if the targetted OS version is at least 10.13, we know this + function is available, so we can unconditionally call it. +- Lastly, we check for the availability of the __builtin_available macro to + potentially insert a dynamic check for this OS version. However, __builtin_available + is only available with sufficiently recent versions of clang and while all + Apple clang versions that ship with Xcode versions that support the 10.13 + SDK support with builtin, we want to allow building with compilers other + than Apple clang that may not support this builtin. + +Signed-off-by: Keno Fischer +--- + hw/9pfs/9p-local.c | 2 +- + hw/9pfs/9p-util-darwin.c | 96 ++++++++++++++++++++++++++++++++++++++++ + hw/9pfs/9p-util-linux.c | 6 +++ + hw/9pfs/9p-util.h | 8 ++++ + hw/9pfs/9p.c | 1 + + 5 files changed, 112 insertions(+), 1 deletion(-) + +diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c +index 8f7e198..35abc51 100644 +--- a/hw/9pfs/9p-local.c ++++ b/hw/9pfs/9p-local.c +@@ -1071,7 +1071,7 @@ static int local_utimensat(FsContext *s, V9fsPath *fs_path, + goto out; + } + +- ret = utimensat(dirfd, name, buf, AT_SYMLINK_NOFOLLOW); ++ ret = utimensat_nofollow(dirfd, name, buf); + close_preserve_errno(dirfd); + out: + g_free(dirpath); +diff --git a/hw/9pfs/9p-util-darwin.c b/hw/9pfs/9p-util-darwin.c +index cdb4c9e..ac414bc 100644 +--- a/hw/9pfs/9p-util-darwin.c ++++ b/hw/9pfs/9p-util-darwin.c +@@ -62,3 +62,99 @@ int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name, + close_preserve_errno(fd); + return ret; + } ++ ++#ifndef __has_builtin ++#define __has_builtin(x) 0 ++#endif ++ ++static int update_times_from_stat(int fd, struct timespec times[2], ++ int update0, int update1) ++{ ++ struct stat buf; ++ int ret = fstat(fd, &buf); ++ if (ret == -1) { ++ return ret; ++ } ++ if (update0) { ++ times[0] = buf.st_atimespec; ++ } ++ if (update1) { ++ times[1] = buf.st_mtimespec; ++ } ++ return 0; ++} ++ ++int utimensat_nofollow(int dirfd, const char *filename, ++ const struct timespec times_in[2]) ++{ ++ int ret, fd; ++ int special0, special1; ++ struct timeval futimes_buf[2]; ++ struct timespec times[2]; ++ memcpy(times, times_in, 2 * sizeof(struct timespec)); ++ ++/* Check whether we have an SDK version that defines utimensat */ ++#if defined(__MAC_10_13) ++# if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_13 ++# define UTIMENSAT_AVAILABLE 1 ++# elif __has_builtin(__builtin_available) ++# define UTIMENSAT_AVAILABLE __builtin_available(macos 10.13, *) ++# else ++# define UTIMENSAT_AVAILABLE 0 ++# endif ++ if (UTIMENSAT_AVAILABLE) { ++ return utimensat(dirfd, filename, times, AT_SYMLINK_NOFOLLOW); ++ } ++#endif ++ ++ /* utimensat not available. Use futimes. */ ++ fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0); ++ if (fd == -1) { ++ return -1; ++ } ++ ++ special0 = times[0].tv_nsec == UTIME_OMIT; ++ special1 = times[1].tv_nsec == UTIME_OMIT; ++ if (special0 || special1) { ++ /* If both are set, nothing to do */ ++ if (special0 && special1) { ++ ret = 0; ++ goto done; ++ } ++ ++ ret = update_times_from_stat(fd, times, special0, special1); ++ if (ret < 0) { ++ goto done; ++ } ++ } ++ ++ special0 = times[0].tv_nsec == UTIME_NOW; ++ special1 = times[1].tv_nsec == UTIME_NOW; ++ if (special0 || special1) { ++ ret = futimes(fd, NULL); ++ if (ret < 0) { ++ goto done; ++ } ++ ++ /* If both are set, we are done */ ++ if (special0 && special1) { ++ ret = 0; ++ goto done; ++ } ++ ++ ret = update_times_from_stat(fd, times, special0, special1); ++ if (ret < 0) { ++ goto done; ++ } ++ } ++ ++ futimes_buf[0].tv_sec = times[0].tv_sec; ++ futimes_buf[0].tv_usec = times[0].tv_nsec / 1000; ++ futimes_buf[1].tv_sec = times[1].tv_sec; ++ futimes_buf[1].tv_usec = times[1].tv_nsec / 1000; ++ ret = futimes(fd, futimes_buf); ++ ++done: ++ close_preserve_errno(fd); ++ return ret; ++} +diff --git a/hw/9pfs/9p-util-linux.c b/hw/9pfs/9p-util-linux.c +index defa3a4..3902378 100644 +--- a/hw/9pfs/9p-util-linux.c ++++ b/hw/9pfs/9p-util-linux.c +@@ -57,3 +57,9 @@ int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name, + g_free(proc_path); + return ret; + } ++ ++int utimensat_nofollow(int dirfd, const char *filename, ++ const struct timespec times[2]) ++{ ++ return utimensat(dirfd, filename, times, AT_SYMLINK_NOFOLLOW); ++} +diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h +index 38ef8b2..1c477a0 100644 +--- a/hw/9pfs/9p-util.h ++++ b/hw/9pfs/9p-util.h +@@ -36,6 +36,12 @@ static inline int qemu_lsetxattr(const char *path, const char *name, + #define qemu_lsetxattr lsetxattr + #endif + ++/* Compatibility with old SDK Versions for Darwin */ ++#if defined(CONFIG_DARWIN) && !defined(UTIME_NOW) ++#define UTIME_NOW -1 ++#define UTIME_OMIT -2 ++#endif ++ + static inline void close_preserve_errno(int fd) + { + int serrno = errno; +@@ -96,5 +102,7 @@ ssize_t flistxattrat_nofollow(int dirfd, const char *filename, + char *list, size_t size); + ssize_t fremovexattrat_nofollow(int dirfd, const char *filename, + const char *name); ++int utimensat_nofollow(int dirfd, const char *filename, ++ const struct timespec times[2]); + + #endif +diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c +index 0fe5976..d8e2bde 100644 +--- a/hw/9pfs/9p.c ++++ b/hw/9pfs/9p.c +@@ -22,6 +22,7 @@ + #include "virtio-9p.h" + #include "fsdev/qemu-fsdev.h" + #include "9p-xattr.h" ++#include "9p-util.h" + #include "coth.h" + #include "trace.h" + #include "migration/blocker.h" +-- +2.30.1 (Apple Git-130) + +From e3b21c7ecaf6cb84e3baef549e133715e51c681e Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Sat, 16 Jun 2018 20:56:55 -0400 +Subject: [PATCH 10/11] 9p: darwin: Implement compatibility for mknodat + +Darwin does not support mknodat. However, to avoid race conditions +with later setting the permissions, we must avoid using mknod on +the full path instead. We could try to fchdir, but that would cause +problems if multiple threads try to call mknodat at the same time. +However, luckily there is a solution: Darwin as an (unexposed in the +C library) system call that sets the cwd for the current thread only. +This should suffice to use mknod safely. + +Signed-off-by: Keno Fischer +--- + hw/9pfs/9p-local.c | 5 +++-- + hw/9pfs/9p-util-darwin.c | 31 +++++++++++++++++++++++++++++++ + hw/9pfs/9p-util-linux.c | 5 +++++ + hw/9pfs/9p-util.h | 2 ++ + 4 files changed, 41 insertions(+), 2 deletions(-) + +diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c +index 35abc51..890e25a 100644 +--- a/hw/9pfs/9p-local.c ++++ b/hw/9pfs/9p-local.c +@@ -668,7 +668,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, + + if (fs_ctx->export_flags & V9FS_SM_MAPPED || + fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { +- err = mknodat(dirfd, name, fs_ctx->fmode | S_IFREG, 0); ++ err = qemu_mknodat(dirfd, name, fs_ctx->fmode | S_IFREG, 0); + if (err == -1) { + goto out; + } +@@ -683,7 +683,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, + } + } else if (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH || + fs_ctx->export_flags & V9FS_SM_NONE) { +- err = mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev); ++ err = qemu_mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev); + if (err == -1) { + goto out; + } +@@ -696,6 +696,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, + + err_end: + unlinkat_preserve_errno(dirfd, name, 0); ++ + out: + close_preserve_errno(dirfd); + return err; +diff --git a/hw/9pfs/9p-util-darwin.c b/hw/9pfs/9p-util-darwin.c +index ac414bc..194f068 100644 +--- a/hw/9pfs/9p-util-darwin.c ++++ b/hw/9pfs/9p-util-darwin.c +@@ -158,3 +158,34 @@ done: + close_preserve_errno(fd); + return ret; + } ++ ++#ifndef SYS___pthread_fchdir ++# define SYS___pthread_fchdir 349 ++#endif ++ ++// This is an undocumented OS X syscall. It would be best to avoid it, ++// but there doesn't seem to be another safe way to implement mknodat. ++// Dear Apple, please implement mknodat before you remove this syscall. ++static int fchdir_thread_local(int fd) ++{ ++#pragma clang diagnostic push ++#pragma clang diagnostic ignored "-Wdeprecated-declarations" ++ return syscall(SYS___pthread_fchdir, fd); ++#pragma clang diagnostic pop ++} ++ ++int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev) ++{ ++ int preserved_errno, err; ++ if (fchdir_thread_local(dirfd) < 0) { ++ return -1; ++ } ++ err = mknod(filename, mode, dev); ++ preserved_errno = errno; ++ /* Stop using the thread-local cwd */ ++ fchdir_thread_local(-1); ++ if (err < 0) { ++ errno = preserved_errno; ++ } ++ return err; ++} +diff --git a/hw/9pfs/9p-util-linux.c b/hw/9pfs/9p-util-linux.c +index 3902378..06399c5 100644 +--- a/hw/9pfs/9p-util-linux.c ++++ b/hw/9pfs/9p-util-linux.c +@@ -63,3 +63,8 @@ int utimensat_nofollow(int dirfd, const char *filename, + { + return utimensat(dirfd, filename, times, AT_SYMLINK_NOFOLLOW); + } ++ ++int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev) ++{ ++ return mknodat(dirfd, filename, mode, dev); ++} +diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h +index 1c477a0..cac682d 100644 +--- a/hw/9pfs/9p-util.h ++++ b/hw/9pfs/9p-util.h +@@ -105,4 +105,6 @@ ssize_t fremovexattrat_nofollow(int dirfd, const char *filename, + int utimensat_nofollow(int dirfd, const char *filename, + const struct timespec times[2]); + ++int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev); ++ + #endif +-- +2.30.1 (Apple Git-130) + +From 9290a25b4b3d85c857ebd601c12a7cc58fe88d42 Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Sat, 16 Jun 2018 20:56:57 -0400 +Subject: [PATCH 11/11] 9p: darwin: meson: Allow VirtFS on Darwin + +Signed-off-by: Keno Fischer +Signed-off-by: Michael Roitzsch +--- + fsdev/meson.build | 1 + + meson.build | 17 ++++++++++------- + 2 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/fsdev/meson.build b/fsdev/meson.build +index adf57cc..b632b66 100644 +--- a/fsdev/meson.build ++++ b/fsdev/meson.build +@@ -7,6 +7,7 @@ fsdev_ss.add(when: ['CONFIG_FSDEV_9P'], if_true: files( + 'qemu-fsdev.c', + ), if_false: files('qemu-fsdev-dummy.c')) + softmmu_ss.add_all(when: 'CONFIG_LINUX', if_true: fsdev_ss) ++softmmu_ss.add_all(when: 'CONFIG_DARWIN', if_true: fsdev_ss) + + if have_virtfs_proxy_helper + executable('virtfs-proxy-helper', +diff --git a/meson.build b/meson.build +index c6f4b0c..d086c96 100644 +--- a/meson.build ++++ b/meson.build +@@ -1060,17 +1060,20 @@ endif + # config-host.h # + ################# + +-have_virtfs = (targetos == 'linux' and +- have_system and +- libattr.found() and +- libcap_ng.found()) ++if targetos == 'linux' ++ have_virtfs = (have_system and ++ libattr.found() and ++ libcap_ng.found()) ++elif targetos == 'darwin' ++ have_virtfs = have_system ++endif + +-have_virtfs_proxy_helper = have_virtfs and have_tools ++have_virtfs_proxy_helper = targetos == 'linux' and have_virtfs and have_tools + + if get_option('virtfs').enabled() + if not have_virtfs +- if targetos != 'linux' +- error('virtio-9p (virtfs) requires Linux') ++ if targetos != 'linux' and targetos != 'darwin' ++ error('virtio-9p (virtfs) requires Linux or Darwin') + elif not libcap_ng.found() or not libattr.found() + error('virtio-9p (virtfs) requires libcap-ng-devel and libattr-devel') + elif not have_system +-- +2.30.1 (Apple Git-130) + diff --git a/pkgs/applications/virtualization/qemu/default.nix b/pkgs/applications/virtualization/qemu/default.nix index f471ac8c064bf..1a93cb875171c 100644 --- a/pkgs/applications/virtualization/qemu/default.nix +++ b/pkgs/applications/virtualization/qemu/default.nix @@ -85,8 +85,9 @@ stdenv.mkDerivation rec { patches = [ ./fix-qemu-ga.patch - ./9p-ignore-noatime.patch - ] ++ optional nixosTestRunner ./force-uid0-on-9p.patch + ] ++ optional (!stdenv.isDarwin) ./9p-ignore-noatime.patch + ++ optional stdenv.isDarwin ./9p-darwin.patch + ++ optional nixosTestRunner ./force-uid0-on-9p.patch ++ optionals stdenv.hostPlatform.isMusl [ (fetchpatch { url = "https://raw.githubusercontent.com/alpinelinux/aports/2bb133986e8fa90e2e76d53369f03861a87a74ef/main/qemu/xattr_size_max.patch";