mirror of
https://github.com/versity/scoutfs.git
synced 2026-01-08 13:01:23 +00:00
scoutfs-utils: add support for inode index items
Add support for the inode index items which are replacing the seq walks from the old btree structures. We create the index items for the root inode, can print out the items, and add a commmand to walk the indices. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -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))
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "sparse.h"
|
||||
#include "util.h"
|
||||
#include "format.h"
|
||||
#include "ioctl.h"
|
||||
#include "cmd.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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#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", "<first> <last> <seq> <path>",
|
||||
"print inodes modified since seq #", inodes_since_cmd);
|
||||
cmd_register("data-since", "<first> <last> <seq> <path>",
|
||||
"print inodes with data blocks modified since seq #", data_since_cmd);
|
||||
}
|
||||
158
utils/src/walk_inodes.c
Normal file
158
utils/src/walk_inodes.c
Normal file
@@ -0,0 +1,158 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#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", "<index> <first> <last> <path>",
|
||||
"print range of indexed inodes", walk_inodes_cmd);
|
||||
}
|
||||
Reference in New Issue
Block a user