From 57da5fae4cfbf72f88caf727cb114a2c2875ec6b Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Fri, 19 Apr 2019 10:49:05 -0700 Subject: [PATCH] scoutfs-utils: add waiting ioctl command Add a quick command that lists the results of the new waiting ioctl. Signed-off-by: Zach Brown --- utils/src/format.h | 5 +- utils/src/ioctl.h | 24 ++++++++++ utils/src/waiting.c | 112 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 utils/src/waiting.c diff --git a/utils/src/format.h b/utils/src/format.h index 936b0717..9fcbc082 100644 --- a/utils/src/format.h +++ b/utils/src/format.h @@ -390,8 +390,9 @@ struct scoutfs_file_extent { __u8 flags; } __packed; -#define SEF_OFFLINE 0x1 -#define SEF_UNWRITTEN 0x2 +#define SEF_OFFLINE (1 << 0) +#define SEF_UNWRITTEN (1 << 1) +#define SEF_UNKNOWN (U8_MAX << 2) /* * The first xattr part item has a header that describes the xattr. The diff --git a/utils/src/ioctl.h b/utils/src/ioctl.h index 915a130b..1b592522 100644 --- a/utils/src/ioctl.h +++ b/utils/src/ioctl.h @@ -229,4 +229,28 @@ enum { #define SCOUTFS_IOC_ITEM_CACHE_KEYS _IOW(SCOUTFS_IOCTL_MAGIC, 8, \ struct scoutfs_ioctl_item_cache_keys) +struct scoutfs_ioctl_data_waiting_entry { + __u64 ino; + __u64 iblock; + __u8 op; +} __packed; + +#define SCOUTFS_IOC_DWO_READ (1 << 0) +#define SCOUTFS_IOC_DWO_WRITE (1 << 1) +#define SCOUTFS_IOC_DWO_CHANGE_SIZE (1 << 2) +#define SCOUTFS_IOC_DWO_UNKNOWN (U8_MAX << 3) + +struct scoutfs_ioctl_data_waiting { + __u64 flags; + __u64 after_ino; + __u64 after_iblock; + __u64 ents_ptr; + __u16 ents_nr; +} __packed; + +#define SCOUTFS_IOC_DATA_WAITING_FLAGS_UNKNOWN (U8_MAX << 0) + +#define SCOUTFS_IOC_DATA_WAITING _IOW(SCOUTFS_IOCTL_MAGIC, 9, \ + struct scoutfs_ioctl_data_waiting) + #endif diff --git a/utils/src/waiting.c b/utils/src/waiting.c new file mode 100644 index 00000000..6e916de0 --- /dev/null +++ b/utils/src/waiting.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sparse.h" +#include "util.h" +#include "format.h" +#include "ioctl.h" +#include "cmd.h" + +static int parse_u64(char *str, u64 *val_ret) +{ + unsigned long long ull; + char *endptr = NULL; + + ull = strtoull(str, &endptr, 0); + if (*endptr != '\0' || + ((ull == LLONG_MIN || ull == LLONG_MAX) && + errno == ERANGE)) { + fprintf(stderr, "invalid 64bit value: '%s'\n", str); + *val_ret = 0; + return -EINVAL; + } + + *val_ret = ull; + + return 0; +} + +#define OP_FMT "%s%s" + +/* + * Print the caller's string for the bit if it's set, and if it's set + * and there are more significant bits coming then we also print a + * separating comma. + */ +#define op_str(ops, bit, str) \ + (((ops) & (bit)) ? (str) : ""), \ + (((ops) & (bit)) && ((ops) & ~(((bit) << 1) - 1)) ? "," : "") + +static int waiting_cmd(int argc, char **argv) +{ + struct scoutfs_ioctl_data_waiting_entry dwe[16]; + struct scoutfs_ioctl_data_waiting idw; + int ret; + int fd; + int i; + + if (argc != 4) { + fprintf(stderr, "must specify ino, iblock, and path\n"); + return -EINVAL; + } + + ret = parse_u64(argv[1], &idw.after_ino) ?: + parse_u64(argv[2], &idw.after_iblock); + if (ret) + return ret; + + fd = open(argv[3], O_RDONLY); + if (fd < 0) { + ret = -errno; + fprintf(stderr, "failed to open '%s': %s (%d)\n", + argv[4], strerror(errno), errno); + return ret; + } + + idw.flags = 0; + idw.ents_ptr = (unsigned long)dwe; + idw.ents_nr = array_size(dwe); + + for (;;) { + ret = ioctl(fd, SCOUTFS_IOC_DATA_WAITING, &idw); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "waiting ioctl failed: %s (%d)\n", + strerror(errno), errno); + break; + } else if (ret == 0) { + break; + } + + for (i = 0; i < ret; i++) + printf("ino %llu iblock %llu ops " + OP_FMT OP_FMT OP_FMT"\n", + dwe[i].ino, dwe[i].iblock, + op_str(dwe[i].op, SCOUTFS_IOC_DWO_READ, + "read"), + op_str(dwe[i].op, SCOUTFS_IOC_DWO_WRITE, + "write"), + op_str(dwe[i].op, SCOUTFS_IOC_DWO_CHANGE_SIZE, + "change_size")); + + idw.after_ino = dwe[i - 1].ino; + idw.after_iblock = dwe[i - 1].iblock; + } + + close(fd); + return ret; +}; + +static void __attribute__((constructor)) waiting_ctor(void) +{ + cmd_register("data-waiting", " ", + "print ops waiting for data blocks", waiting_cmd); +}