From 932b0776d1d498847ede3f6f6ff08afc91d1e5f6 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 15 Nov 2016 17:53:00 -0800 Subject: [PATCH] Add commands for working with offline data Add the data_version, stage, and release commands for working with offline extents of file data. Signed-off-by: Zach Brown --- utils/src/ioctl.h | 28 +++++ utils/src/stage_release.c | 233 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 261 insertions(+) create mode 100644 utils/src/stage_release.c diff --git a/utils/src/ioctl.h b/utils/src/ioctl.h index e5598103..75e11343 100644 --- a/utils/src/ioctl.h +++ b/utils/src/ioctl.h @@ -53,4 +53,32 @@ struct scoutfs_ioctl_find_xattr { #define SCOUTFS_IOC_INODE_DATA_SINCE _IOW(SCOUTFS_IOCTL_MAGIC, 5, \ struct scoutfs_ioctl_inodes_since) + +struct scoutfs_ioctl_data_version { + __u64 ino; + __u64 data_version; +} __packed; + +#define SCOUTFS_IOC_DATA_VERSION _IOW(SCOUTFS_IOCTL_MAGIC, 6, \ + struct scoutfs_ioctl_data_version) + +struct scoutfs_ioctl_release { + __u64 offset; + __u64 count; + __u64 data_version; +} __packed; + +#define SCOUTFS_IOC_RELEASE _IOW(SCOUTFS_IOCTL_MAGIC, 7, \ + struct scoutfs_ioctl_release) + +struct scoutfs_ioctl_stage { + __u64 data_version; + __u64 buf_ptr; + __u64 offset; + __s32 count; +} __packed; + +#define SCOUTFS_IOC_STAGE _IOW(SCOUTFS_IOCTL_MAGIC, 8, \ + struct scoutfs_ioctl_stage) + #endif diff --git a/utils/src/stage_release.c b/utils/src/stage_release.c new file mode 100644 index 00000000..581cb69f --- /dev/null +++ b/utils/src/stage_release.c @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sparse.h" +#include "util.h" +#include "ioctl.h" +#include "cmd.h" + +static int stage_cmd(int argc, char **argv) +{ + struct scoutfs_ioctl_stage args; + char *endptr = NULL; + char *buf = NULL; + int afd = -1; + int fd = -1; + u64 offset; + u64 count; + u64 vers; + int ret; + + if (argc != 5) { + fprintf(stderr, "must specify moar args\n"); + return -EINVAL; + } + + fd = open(argv[0], O_RDWR); + if (fd < 0) { + ret = -errno; + fprintf(stderr, "failed to open '%s': %s (%d)\n", + argv[0], strerror(errno), errno); + return ret; + } + + vers = strtoull(argv[1], &endptr, 0); + if (*endptr != '\0' || + ((vers == LLONG_MIN || vers == LLONG_MAX) && errno == ERANGE)) { + fprintf(stderr, "error parsing data version '%s'\n", + argv[1]); + ret = -EINVAL; + goto out; + } + + offset = strtoull(argv[2], &endptr, 0); + if (*endptr != '\0' || + ((offset == LLONG_MIN || offset == LLONG_MAX) && errno == ERANGE)) { + fprintf(stderr, "error parsing offset '%s'\n", + argv[2]); + ret = -EINVAL; + goto out; + } + + count = strtoull(argv[3], &endptr, 0); + if (*endptr != '\0' || + ((count == LLONG_MIN || count == LLONG_MAX) && errno == ERANGE)) { + fprintf(stderr, "error parsing count '%s'\n", + argv[3]); + ret = -EINVAL; + goto out; + } + + if (count > INT_MAX) { + fprintf(stderr, "count %llu too large, limited to %d\n", + count, INT_MAX); + ret = -EINVAL; + goto out; + } + + afd = open(argv[4], O_RDONLY); + if (afd < 0) { + ret = -errno; + fprintf(stderr, "failed to open '%s': %s (%d)\n", + argv[4], strerror(errno), errno); + goto out; + } + + buf = malloc(count); + if (!buf) { + fprintf(stderr, "couldn't allocate %llu byte buffer\n", + count); + ret = -ENOMEM; + goto out; + } + + ret = read(afd, buf, count); + if (ret < count) { + fprintf(stderr, "archive read returned %d, not %llu: error %s (%d)\n", + ret, count, strerror(errno), errno); + ret = -EIO; + goto out; + } + + args.data_version = vers; + args.buf_ptr = (unsigned long)buf; + args.offset = offset; + args.count = count; + + ret = ioctl(fd, SCOUTFS_IOC_STAGE, &args); + if (ret < count) { + fprintf(stderr, "stage returned %d, not %llu: error %s (%d)\n", + ret, count, strerror(errno), errno); + ret = -EIO; + } +out: + free(buf); + if (fd > -1) + close(fd); + if (afd > -1) + close(afd); + return ret; +}; + +static void __attribute__((constructor)) stage_ctor(void) +{ + cmd_register("stage", " ", + "write archive file contents to offline region", stage_cmd); +} + +static int release_cmd(int argc, char **argv) +{ + struct scoutfs_ioctl_release args; + char *endptr = NULL; + u64 offset; + u64 count; + u64 vers; + int ret; + int fd; + + if (argc != 4) { + fprintf(stderr, "must specify path, data version, offset, and count\n"); + return -EINVAL; + } + + fd = open(argv[0], O_RDWR); + if (fd < 0) { + ret = -errno; + fprintf(stderr, "failed to open '%s': %s (%d)\n", + argv[0], strerror(errno), errno); + return ret; + } + + vers = strtoull(argv[1], &endptr, 0); + if (*endptr != '\0' || + ((vers == LLONG_MIN || vers == LLONG_MAX) && errno == ERANGE)) { + fprintf(stderr, "error parsing data version '%s'\n", + argv[1]); + ret = -EINVAL; + goto out; + } + + offset = strtoull(argv[2], &endptr, 0); + if (*endptr != '\0' || + ((offset == LLONG_MIN || offset == LLONG_MAX) && errno == ERANGE)) { + fprintf(stderr, "error parsing starting offset '%s'\n", + argv[2]); + ret = -EINVAL; + goto out; + } + + count = strtoull(argv[3], &endptr, 0); + if (*endptr != '\0' || + ((count == LLONG_MIN || count == LLONG_MAX) && errno == ERANGE)) { + fprintf(stderr, "error parsing length '%s'\n", + argv[3]); + ret = -EINVAL; + goto out; + } + + args.offset = offset; + args.count = count; + args.data_version = vers; + + ret = ioctl(fd, SCOUTFS_IOC_RELEASE, &args); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "release ioctl failed: %s (%d)\n", + strerror(errno), errno); + } +out: + close(fd); + return ret; +}; + +static void __attribute__((constructor)) release_ctor(void) +{ + cmd_register("release", " ", + "mark file region offline and free extents", release_cmd); +} + +static int data_version_cmd(int argc, char **argv) +{ + u64 vers; + int ret; + int fd; + + if (argc != 1) { + fprintf(stderr, "must specify path\n"); + return -EINVAL; + } + + fd = open(argv[0], O_RDWR); + if (fd < 0) { + ret = -errno; + fprintf(stderr, "failed to open '%s': %s (%d)\n", + argv[0], strerror(errno), errno); + return ret; + } + + ret = ioctl(fd, SCOUTFS_IOC_DATA_VERSION, &vers); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "data version ioctl failed: %s (%d)\n", + strerror(errno), errno); + } else { + printf("%llu\n", vers); + } + + close(fd); + return ret; +}; + +static void __attribute__((constructor)) data_version_ctor(void) +{ + cmd_register("data_version", "", + "print the file's data version", data_version_cmd); +}