diff --git a/utils/src/format.h b/utils/src/format.h index 63cc07be..7e91afa1 100644 --- a/utils/src/format.h +++ b/utils/src/format.h @@ -160,6 +160,9 @@ struct scoutfs_segment_block { #define SCOUTFS_ORPHAN_KEY 10 #define SCOUTFS_FREE_EXTENT_BLKNO_KEY 11 #define SCOUTFS_FREE_EXTENT_BLOCKS_KEY 12 +#define SCOUTFS_INODE_INDEX_CTIME_KEY 13 +#define SCOUTFS_INODE_INDEX_MTIME_KEY 14 +#define SCOUTFS_INODE_INDEX_SIZE_KEY 15 /* not found in the fs */ #define SCOUTFS_MAX_UNUSED_KEY 253 #define SCOUTFS_NET_ADDR_KEY 254 @@ -249,6 +252,18 @@ struct scoutfs_symlink_key { __be64 ino; } __packed; +struct scoutfs_betimespec { + __be64 sec; + __be32 nsec; +} __packed; + +struct scoutfs_inode_index_key { + __u8 type; + __be64 major; + __be32 minor; + __be64 ino; +} __packed; + /* XXX does this exist upstream somewhere? */ #define member_sizeof(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER)) diff --git a/utils/src/ino_path.c b/utils/src/ino_path.c index 69c50892..36fe0535 100644 --- a/utils/src/ino_path.c +++ b/utils/src/ino_path.c @@ -11,6 +11,7 @@ #include "sparse.h" #include "util.h" +#include "format.h" #include "ioctl.h" #include "cmd.h" diff --git a/utils/src/ioctl.h b/utils/src/ioctl.h index 190199fc..864b9b8f 100644 --- a/utils/src/ioctl.h +++ b/utils/src/ioctl.h @@ -1,30 +1,36 @@ #ifndef _SCOUTFS_IOCTL_H_ #define _SCOUTFS_IOCTL_H_ -#include "format.h" - /* XXX I have no idea how these are chosen. */ #define SCOUTFS_IOCTL_MAGIC 's' -struct scoutfs_ioctl_ino_seq { +struct scoutfs_ioctl_walk_inodes_entry { + __u64 major; + __u32 minor; __u64 ino; - __u64 seq; } __packed; -struct scoutfs_ioctl_inodes_since { - __u64 first_ino; - __u64 last_ino; - __u64 seq; - __u64 buf_ptr; - __u32 buf_len; +struct scoutfs_ioctl_walk_inodes { + struct scoutfs_ioctl_walk_inodes_entry first; + struct scoutfs_ioctl_walk_inodes_entry last; + __u64 entries_ptr; + __u32 nr_entries; + __u8 index; } __packed; +enum { + SCOUTFS_IOC_WALK_INODES_CTIME = 0, + SCOUTFS_IOC_WALK_INODES_MTIME, + SCOUTFS_IOC_WALK_INODES_SIZE, + SCOUTFS_IOC_WALK_INODES_UNKNOWN, +}; + /* - * Adds entries to the user's buffer for each inode whose sequence - * number is greater than or equal to the given seq. + * Adds entries to the user's buffer for each inode that is found in the + * given index between the first and last positions. */ -#define SCOUTFS_IOC_INODES_SINCE _IOW(SCOUTFS_IOCTL_MAGIC, 1, \ - struct scoutfs_ioctl_inodes_since) +#define SCOUTFS_IOC_WALK_INODES _IOW(SCOUTFS_IOCTL_MAGIC, 1, \ + struct scoutfs_ioctl_walk_inodes) /* * Fill the path buffer with the next path to the target inode. An @@ -80,10 +86,7 @@ struct scoutfs_ioctl_ino_path { #define SCOUTFS_IOC_INO_PATH _IOW(SCOUTFS_IOCTL_MAGIC, 2, \ struct scoutfs_ioctl_ino_path) -#define SCOUTFS_IOC_INODE_DATA_SINCE _IOW(SCOUTFS_IOCTL_MAGIC, 3, \ - struct scoutfs_ioctl_inodes_since) - -#define SCOUTFS_IOC_DATA_VERSION _IOW(SCOUTFS_IOCTL_MAGIC, 4, u64) +#define SCOUTFS_IOC_DATA_VERSION _IOW(SCOUTFS_IOCTL_MAGIC, 4, __u64) struct scoutfs_ioctl_release { __u64 offset; diff --git a/utils/src/mkfs.c b/utils/src/mkfs.c index e416fc88..005723d8 100644 --- a/utils/src/mkfs.c +++ b/utils/src/mkfs.c @@ -75,8 +75,8 @@ static u64 calc_ring_blocks(u64 max_nr, u64 max_size) static int write_new_fs(char *path, int fd) { struct scoutfs_super_block *super; - struct scoutfs_inode_key root_ikey; struct scoutfs_inode_key *ikey; + struct scoutfs_inode_index_key *idx_key; struct scoutfs_inode *inode; struct scoutfs_segment_block *sblk; struct scoutfs_manifest_entry *ment; @@ -124,10 +124,6 @@ static int write_new_fs(char *path, int fd) total_segs = size / SCOUTFS_SEGMENT_SIZE; - /* segments and manifest entries all use single key */ - root_ikey.type = SCOUTFS_INODE_KEY; - root_ikey.ino = cpu_to_be64(SCOUTFS_ROOT_INO); - /* partially initialize the super so we can use it to init others */ memset(super, 0, SCOUTFS_BLOCK_SIZE); pseudo_random_bytes(&super->hdr.fsid, sizeof(super->hdr.fsid)); @@ -184,17 +180,23 @@ static int write_new_fs(char *path, int fd) rent = rblk->entries; rent->flags = 0; rent->data_len = cpu_to_le16(sizeof(struct scoutfs_manifest_entry) + - (2 * sizeof(struct scoutfs_inode_key))); + sizeof(struct scoutfs_inode_key) + + sizeof(struct scoutfs_inode_index_key)); ment = (void *)rent->data; ment->segno = cpu_to_le64(first_segno); ment->seq = cpu_to_le64(1); ment->first_key_len = cpu_to_le16(sizeof(struct scoutfs_inode_key)); - ment->last_key_len = cpu_to_le16(sizeof(struct scoutfs_inode_key)); + ment->last_key_len = cpu_to_le16(sizeof(struct scoutfs_inode_index_key)); ment->level = 1; ikey = (void *)ment->keys; - ikey[0] = root_ikey; - ikey[1] = root_ikey; + ikey->type = SCOUTFS_INODE_KEY; + ikey->ino = cpu_to_be64(SCOUTFS_ROOT_INO); + idx_key = (void *)(ikey + 1); + idx_key->type = SCOUTFS_INODE_INDEX_SIZE_KEY; + idx_key->major = cpu_to_be64(0); + idx_key->minor = 0; + idx_key->ino = cpu_to_be64(SCOUTFS_ROOT_INO); rblk->crc = cpu_to_le32(crc_ring_block(rblk)); @@ -210,11 +212,12 @@ static int write_new_fs(char *path, int fd) /* write seg with root inode */ sblk->segno = cpu_to_le64(first_segno); sblk->seq = cpu_to_le64(1); - sblk->nr_items = cpu_to_le32(1); + sblk->nr_items = cpu_to_le32(4); item = &sblk->items[0]; - ikey = (void *)&sblk->items[1]; - inode = (void *)(ikey + 1); + ikey = (void *)&sblk->items[4]; + inode = (void *)(ikey + 1) + + (3 * sizeof(struct scoutfs_inode_index_key)); item->seq = cpu_to_le64(1); item->key_off = cpu_to_le32((long)ikey - (long)sblk); @@ -222,7 +225,8 @@ static int write_new_fs(char *path, int fd) item->key_len = cpu_to_le16(sizeof(struct scoutfs_inode_key)); item->val_len = cpu_to_le16(sizeof(struct scoutfs_inode)); - *ikey = root_ikey; + ikey->type = SCOUTFS_INODE_KEY; + ikey->ino = cpu_to_be64(SCOUTFS_ROOT_INO); inode->next_readdir_pos = cpu_to_le64(2); inode->nlink = cpu_to_le32(SCOUTFS_DIRENT_FIRST_POS); @@ -234,6 +238,38 @@ static int write_new_fs(char *path, int fd) inode->mtime.sec = inode->atime.sec; inode->mtime.nsec = inode->atime.nsec; + item = (void *)(item + 1); + idx_key = (void *)(ikey + 1); + + /* write the root inode index keys */ + for (i = SCOUTFS_INODE_INDEX_CTIME_KEY; + i <= SCOUTFS_INODE_INDEX_SIZE_KEY; i++) { + + item->seq = cpu_to_le64(1); + item->key_off = cpu_to_le32((long)idx_key - (long)sblk); + item->val_off = 0; + item->key_len = cpu_to_le16(sizeof(*idx_key)); + item->val_len = 0; + + idx_key->type = i; + idx_key->ino = cpu_to_be64(SCOUTFS_ROOT_INO); + + switch(i) { + case SCOUTFS_INODE_INDEX_CTIME_KEY: + case SCOUTFS_INODE_INDEX_MTIME_KEY: + idx_key->major = cpu_to_be64(tv.tv_sec); + idx_key->minor = cpu_to_be32(tv.tv_usec * 1000); + break; + case SCOUTFS_INODE_INDEX_SIZE_KEY: + idx_key->major = cpu_to_be64(0); + idx_key->minor = 0; + break; + } + + item = (void *)(item + 1); + idx_key = (void *)(idx_key + 1); + } + ret = pwrite(fd, sblk, SCOUTFS_SEGMENT_SIZE, first_segno << SCOUTFS_SEGMENT_SHIFT); if (ret != SCOUTFS_SEGMENT_SIZE) { diff --git a/utils/src/print.c b/utils/src/print.c index 8921d182..9dd03192 100644 --- a/utils/src/print.c +++ b/utils/src/print.c @@ -225,6 +225,15 @@ static void print_free_extent(void *key, int key_len, void *val, int val_len) str, node_id, blkno, blocks); } +static void print_inode_index(void *key, int key_len, void *val, int val_len) +{ + struct scoutfs_inode_index_key *ikey = key; + + printf(" index: major %llu minor %u ino %llu\n", + be64_to_cpu(ikey->major), be32_to_cpu(ikey->minor), + be64_to_cpu(ikey->ino)); +} + typedef void (*print_func_t)(void *key, int key_len, void *val, int val_len); static print_func_t printers[] = { @@ -238,6 +247,9 @@ static print_func_t printers[] = { [SCOUTFS_FILE_EXTENT_KEY] = print_file_extent, [SCOUTFS_FREE_EXTENT_BLKNO_KEY] = print_free_extent, [SCOUTFS_FREE_EXTENT_BLOCKS_KEY] = print_free_extent, + [SCOUTFS_INODE_INDEX_CTIME_KEY] = print_inode_index, + [SCOUTFS_INODE_INDEX_MTIME_KEY] = print_inode_index, + [SCOUTFS_INODE_INDEX_SIZE_KEY] = print_inode_index, }; /* utils uses big contiguous allocations */ diff --git a/utils/src/since.c b/utils/src/since.c deleted file mode 100644 index d62db300..00000000 --- a/utils/src/since.c +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sparse.h" -#include "util.h" -#include "ioctl.h" -#include "cmd.h" - -static int since_cmd(int argc, char **argv, unsigned long ioc) -{ - struct scoutfs_ioctl_inodes_since args; - struct scoutfs_ioctl_ino_seq *iseq; - int len = 4 * 1024 * 1024; - char *endptr; - u64 nrs[3]; - void *ptr; - int ret; - int fd; - u64 n; - int i; - - if (argc != 4) { - fprintf(stderr, "must specify seq and path\n"); - return -EINVAL; - } - - for (i = 0; i < array_size(nrs); i++) { - n = strtoull(argv[i], &endptr, 0); - if (*endptr != '\0' || - ((n == LLONG_MIN || n == LLONG_MAX) && errno == ERANGE)) { - fprintf(stderr, "error parsing 64bit value '%s'\n", - argv[i]); - return -EINVAL; - } - nrs[i] = n; - } - - fd = open(argv[3], O_RDONLY); - if (fd < 0) { - ret = -errno; - fprintf(stderr, "failed to open '%s': %s (%d)\n", - argv[3], strerror(errno), errno); - return ret; - } - - ptr = malloc(len); - if (!ptr) { - fprintf(stderr, "must specify seq and path\n"); - close(fd); - return -EINVAL; - } - - args.first_ino = nrs[0]; - args.last_ino = nrs[1]; - args.seq = nrs[2]; - args.buf_ptr = (intptr_t)ptr; - args.buf_len = len; - - ret = ioctl(fd, ioc, &args); - if (ret < 0) { - ret = -errno; - fprintf(stderr, "inodes_since ioctl failed: %s (%d)\n", - strerror(errno), errno); - goto out; - } - - n = ret / sizeof(*iseq); - for (i = 0, iseq = ptr; i < n; i++, iseq++) - printf("ino %llu seq %llu\n", iseq->ino, iseq->seq); - -out: - free(ptr); - close(fd); - return ret; -}; - -static int inodes_since_cmd(int argc, char **argv) -{ - return since_cmd(argc, argv, SCOUTFS_IOC_INODES_SINCE); -} - -static int data_since_cmd(int argc, char **argv) -{ - return since_cmd(argc, argv, SCOUTFS_IOC_INODE_DATA_SINCE); -} - -static void __attribute__((constructor)) since_ctor(void) -{ - cmd_register("inodes-since", " ", - "print inodes modified since seq #", inodes_since_cmd); - cmd_register("data-since", " ", - "print inodes with data blocks modified since seq #", data_since_cmd); -} diff --git a/utils/src/walk_inodes.c b/utils/src/walk_inodes.c new file mode 100644 index 00000000..80ef6d6c --- /dev/null +++ b/utils/src/walk_inodes.c @@ -0,0 +1,158 @@ +#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" + +/* + * Parse the command line specification of a walk inodes entry of the + * form "major.minor.ino". At least one value must be given, the rest + * default to 0. + */ +static int parse_walk_entry(struct scoutfs_ioctl_walk_inodes_entry *ent, + char *str) +{ + char *endptr; + char *c; + u64 ull; + u64 minor; + u64 *val; + + memset(ent, 0, sizeof(*ent)); + val = &ent->major; + + for (;;) { + c = index(str, '.'); + if (c) + *c = '\0'; + + endptr = NULL; + ull = strtoull(str, &endptr, 0); + if (*endptr != '\0' || + ((ull == LLONG_MIN || ull == LLONG_MAX) && + errno == ERANGE) || + (val == &minor && (*val < INT_MIN || *val > INT_MAX))) { + fprintf(stderr, "bad index pos at '%s'\n", str); + return -EINVAL; + } + + *val = ull; + + if (val == &ent->major) + val = &minor; + else if (val == &minor) + val = &ent->ino; + else + break; + + if (c) + str = c + 1; + else + break; + } + + ent->minor = minor; + return 0; +} + +static int walk_inodes_cmd(int argc, char **argv) +{ + struct scoutfs_ioctl_walk_inodes_entry ents[128]; + struct scoutfs_ioctl_walk_inodes walk; + u64 total = 0; + int ret; + int fd; + int i; + + if (argc != 4) { + fprintf(stderr, "must specify seq and path\n"); + return -EINVAL; + } + + if (!strcasecmp(argv[0], "size")) + walk.index = SCOUTFS_IOC_WALK_INODES_SIZE; + else if (!strcasecmp(argv[0], "ctime")) + walk.index = SCOUTFS_IOC_WALK_INODES_CTIME; + else if (!strcasecmp(argv[0], "mtime")) + walk.index = SCOUTFS_IOC_WALK_INODES_MTIME; + else { + fprintf(stderr, "unknown index '%s', try 'size', 'ctime, or " + "mtime'\n", argv[0]); + return -EINVAL; + } + + ret = parse_walk_entry(&walk.first, argv[1]); + if (ret) { + fprintf(stderr, "invalid first position '%s', try '1.2.3' or " + "'-1'\n", argv[1]); + return -EINVAL; + + } + + ret = parse_walk_entry(&walk.last, argv[2]); + if (ret) { + fprintf(stderr, "invalid last position '%s', try '1.2.3' or " + "'-1'\n", argv[2]); + return -EINVAL; + + } + + fd = open(argv[3], O_RDONLY); + if (fd < 0) { + ret = -errno; + fprintf(stderr, "failed to open '%s': %s (%d)\n", + argv[3], strerror(errno), errno); + return ret; + } + + walk.entries_ptr = (unsigned long)ents; + walk.nr_entries = array_size(ents); + + for (;;) { + ret = ioctl(fd, SCOUTFS_IOC_WALK_INODES, &walk); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "walk_inodes ioctl failed: %s (%d)\n", + strerror(errno), errno); + break; + } else if (ret == 0) { + break; + } + + for (i = 0; i < ret; i++) { + if ((total + i) % 25 == 0) + printf("%-20s %-20s %-10s %-20s\n", + "#", "major", "minor", "ino"); + + printf("%-20llu %-20llu %-10u %-20llu\n", + total + i, ents[i].major, ents[i].minor, + ents[i].ino); + } + + total += i; + + walk.first = ents[i - 1]; + if (++walk.first.ino == 0 && ++walk.first.minor == 0) + walk.first.major++; + } + + close(fd); + return ret; +}; + +static void __attribute__((constructor)) walk_inodes_ctor(void) +{ + cmd_register("walk-inodes", " ", + "print range of indexed inodes", walk_inodes_cmd); +}