diff options
-rw-r--r-- | fsdev/virtfs-proxy-helper.c | 86 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p-proxy.c | 32 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p-proxy.h | 1 |
3 files changed, 119 insertions, 0 deletions
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c index 703ac8567f..52d748d93a 100644 --- a/fsdev/virtfs-proxy-helper.c +++ b/fsdev/virtfs-proxy-helper.c @@ -28,6 +28,11 @@ #include <sys/vfs.h> #include <sys/stat.h> #include <attr/xattr.h> +#include <sys/ioctl.h> +#include <linux/fs.h> +#ifdef CONFIG_LINUX_MAGIC_H +#include <linux/magic.h> +#endif #include "qemu-common.h" #include "virtio-9p-marshal.h" #include "hw/9pfs/virtio-9p-proxy.h" @@ -35,6 +40,19 @@ #define PROGNAME "virtfs-proxy-helper" +#ifndef XFS_SUPER_MAGIC +#define XFS_SUPER_MAGIC 0x58465342 +#endif +#ifndef EXT2_SUPER_MAGIC +#define EXT2_SUPER_MAGIC 0xEF53 +#endif +#ifndef REISERFS_SUPER_MAGIC +#define REISERFS_SUPER_MAGIC 0x52654973 +#endif +#ifndef BTRFS_SUPER_MAGIC +#define BTRFS_SUPER_MAGIC 0x9123683E +#endif + static struct option helper_opts[] = { {"fd", required_argument, NULL, 'f'}, {"path", required_argument, NULL, 'p'}, @@ -42,6 +60,7 @@ static struct option helper_opts[] = { }; static bool is_daemon; +static bool get_version; /* IOC getversion IOCTL supported */ static void do_log(int loglevel, const char *format, ...) { @@ -330,6 +349,49 @@ static int send_response(int sock, struct iovec *iovec, int size) return 0; } +/* + * gets generation number + * returns -errno on failure and sizeof(generation number) on success + */ +static int do_getversion(struct iovec *iovec, struct iovec *out_iovec) +{ + uint64_t version; + int retval = -ENOTTY; +#ifdef FS_IOC_GETVERSION + int fd; + V9fsString path; +#endif + + + /* no need to issue ioctl */ + if (!get_version) { + version = 0; + retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, "q", version); + return retval; + } +#ifdef FS_IOC_GETVERSION + retval = proxy_unmarshal(iovec, PROXY_HDR_SZ, "s", &path); + if (retval < 0) { + return retval; + } + + fd = open(path.data, O_RDONLY); + if (fd < 0) { + retval = -errno; + goto err_out; + } + if (ioctl(fd, FS_IOC_GETVERSION, &version) < 0) { + retval = -errno; + } else { + retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, "q", version); + } + close(fd); +err_out: + v9fs_string_free(&path); +#endif + return retval; +} + static int do_getxattr(int type, struct iovec *iovec, struct iovec *out_iovec) { int size = 0, offset, retval; @@ -673,6 +735,7 @@ static int process_reply(int sock, int type, case T_READLINK: case T_LGETXATTR: case T_LLISTXATTR: + case T_GETVERSION: if (send_response(sock, out_iovec, retval) < 0) { return -1; } @@ -855,6 +918,9 @@ static int process_requests(int sock) v9fs_string_free(&path); v9fs_string_free(&name); break; + case T_GETVERSION: + retval = do_getversion(&in_iovec, &out_iovec); + break; default: goto err_out; break; @@ -876,6 +942,10 @@ int main(int argc, char **argv) char *rpath = NULL; struct stat stbuf; int c, option_index; +#ifdef FS_IOC_GETVERSION + int retval; + struct statfs st_fs; +#endif is_daemon = true; sock = -1; @@ -932,6 +1002,22 @@ int main(int argc, char **argv) do_log(LOG_INFO, "Started\n"); + get_version = false; +#ifdef FS_IOC_GETVERSION + /* check whether underlying FS support IOC_GETVERSION */ + retval = statfs(rpath, &st_fs); + if (!retval) { + switch (st_fs.f_type) { + case EXT2_SUPER_MAGIC: + case BTRFS_SUPER_MAGIC: + case REISERFS_SUPER_MAGIC: + case XFS_SUPER_MAGIC: + get_version = true; + break; + } + } +#endif + if (chdir("/") < 0) { do_perror("chdir"); goto error; diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c index 22e9b68342..415bd21815 100644 --- a/hw/9pfs/virtio-9p-proxy.c +++ b/hw/9pfs/virtio-9p-proxy.c @@ -243,6 +243,9 @@ static int v9fs_receive_response(V9fsProxy *proxy, int type, v9fs_string_free(&xattr); break; } + case T_GETVERSION: + proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response); + break; default: return -1; } @@ -509,6 +512,14 @@ static int v9fs_request(V9fsProxy *proxy, int type, 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\n", type); retval = -EINVAL; @@ -559,6 +570,7 @@ static int v9fs_request(V9fsProxy *proxy, int type, case T_LSTAT: case T_READLINK: case T_STATFS: + case T_GETVERSION: if (v9fs_receive_response(proxy, type, &retval, response) < 0) { goto close_error; } @@ -1064,6 +1076,25 @@ static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir, 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)) { + return 0; + } + err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, "s", path); + if (err < 0) { + errno = -err; + err = -1; + } + return err; +} + static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs) { const char *sock_fd = qemu_opt_get(opts, "sock_fd"); @@ -1098,6 +1129,7 @@ static int proxy_init(FsContext *ctx) qemu_mutex_init(&proxy->mutex); ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; + ctx->exops.get_st_gen = proxy_ioc_getversion; return 0; } diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h index 7b3b0a9a39..005c1ad757 100644 --- a/hw/9pfs/virtio-9p-proxy.h +++ b/hw/9pfs/virtio-9p-proxy.h @@ -58,6 +58,7 @@ enum { T_LLISTXATTR, T_LSETXATTR, T_LREMOVEXATTR, + T_GETVERSION, }; typedef struct { |