diff --git a/utils/src/cmp.h b/utils/src/cmp.h new file mode 100644 index 00000000..23c6d8a6 --- /dev/null +++ b/utils/src/cmp.h @@ -0,0 +1,23 @@ +#ifndef _SCOUTFS_CMP_H_ +#define _SCOUTFS_CMP_H_ + +/* + * A generic ternary comparison macro with strict type checking. + */ +#define scoutfs_cmp(a, b) \ +({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + int _ret; \ + \ + (void) (&_a == &_b); \ + _ret = _a < _b ? -1 : _a > _b ? 1 : 0; \ + _ret; \ +}) + +static inline int scoutfs_cmp_u64s(u64 a, u64 b) +{ + return a < b ? -1 : a > b ? 1 : 0; +} + +#endif diff --git a/utils/src/endian_swap.h b/utils/src/endian_swap.h new file mode 100644 index 00000000..e64d119e --- /dev/null +++ b/utils/src/endian_swap.h @@ -0,0 +1,12 @@ +#ifndef _SCOUTFS_ENDIAN_SWAP_H_ +#define _SCOUTFS_ENDIAN_SWAP_H_ + +#define le64_to_be64(x) cpu_to_be64(le64_to_cpu(x)) +#define le32_to_be32(x) cpu_to_be32(le32_to_cpu(x)) +#define le16_to_be16(x) cpu_to_be16(le16_to_cpu(x)) + +#define be64_to_le64(x) cpu_to_le64(be64_to_cpu(x)) +#define be32_to_le32(x) cpu_to_le32(be32_to_cpu(x)) +#define be16_to_le16(x) cpu_to_le16(be16_to_cpu(x)) + +#endif diff --git a/utils/src/format.h b/utils/src/format.h index 0509e647..27e467a5 100644 --- a/utils/src/format.h +++ b/utils/src/format.h @@ -52,6 +52,75 @@ struct scoutfs_block_header { __le64 blkno; } __packed; +/* + * scoutfs identifies all file system metadata items by a small key + * struct. + * + * Each item type maps their logical structures to the fixed fields in + * sort order. This lets us print keys without needing per-type + * formats. + * + * The keys are compared by considering the fields in struct order from + * most to least significant. They are considered a multi precision + * value when navigating the keys in ordered key space. We can + * increment them, subtract them from each other, etc. + */ +struct scoutfs_key { + __u8 sk_zone; + __le64 _sk_first; + __u8 sk_type; + __le64 _sk_second; + __le64 _sk_third; + __u8 _sk_fourth; +}__packed; + +/* inode index */ +#define skii_major _sk_second +#define skii_ino _sk_third + +/* node free bit map */ +#define skf_node_id _sk_first +#define skf_base _sk_second + +/* node orphan inode */ +#define sko_node_id _sk_first +#define sko_ino _sk_second + +/* inode */ +#define ski_ino _sk_first + +/* xattr parts */ +#define skx_ino _sk_first +#define skx_name_hash _sk_second +#define skx_id _sk_third +#define skx_part _sk_fourth + +/* directory entries */ +#define skd_ino _sk_first +#define skd_major _sk_second +#define skd_minor _sk_third + +/* symlink target */ +#define sks_ino _sk_first +#define sks_nr _sk_second + +/* file data mapping */ +#define skm_ino _sk_first +#define skm_base _sk_second + +/* + * The btree still uses memcmp() to compare keys. We should fix that + * before too long. + */ +struct scoutfs_key_be { + __u8 sk_zone; + __be64 _sk_first; + __u8 sk_type; + __be64 _sk_second; + __be64 _sk_third; + __u8 _sk_fourth; +}__packed; + /* * Assert that we'll be able to represent all possible keys with 8 64bit * primary sort values. @@ -143,34 +212,24 @@ struct scoutfs_manifest { } __packed; /* - * Manifest entries are packed into btree keys and values in a very - * fiddly way so that we can sort them with memcmp first by level then - * by their position in the level. First comes the level. + * Manifest entries are split across btree keys and values. Putting + * some entry fields in the value keeps the key smaller and increases + * the fanout of the btree which keeps the tree smaller and reduces + * block IO. * - * Level 0 segments are sorted by their seq so they don't have the first - * segment key in the manifest btree key. Both of their keys are in the - * value. - * - * Level 1 segments are sorted by their first key so their last key is - * in the value. - * - * We go to all this trouble so that we can communicate a version of the - * manifest with one btree root, have dense btree keys which are used as - * seperators in parent blocks, and don't duplicate the large keys in - * the manifest btree key and value. + * The key is made up of the level, first key, and seq. At level 0 + * segments can completely overlap and have identical key ranges but we + * avoid duplicate btree keys by including the unique seq. */ - struct scoutfs_manifest_btree_key { __u8 level; - __u8 bkey[0]; + struct scoutfs_key_be first_key; + __be64 seq; } __packed; struct scoutfs_manifest_btree_val { __le64 segno; - __le64 seq; - __le16 first_key_len; - __le16 last_key_len; - __u8 keys[0]; + struct scoutfs_key last_key; } __packed; #define SCOUTFS_ALLOC_REGION_SHIFT 8 @@ -201,15 +260,12 @@ struct scoutfs_alloc_region_btree_val { * They're not allowed to cross a block boundary. */ struct scoutfs_segment_item { - __le16 key_len; + struct scoutfs_key key; __le16 val_len; __u8 flags; __u8 nr_links; __le32 skip_links[0]; - /* - * __u8 key_bytes[key_len] - * __u8 val_bytes[val_len] - */ + /* __u8 val_bytes[val_len] */ } __packed; #define SCOUTFS_ITEM_FLAG_DELETION (1 << 0) @@ -259,30 +315,6 @@ struct scoutfs_segment_block { #define SCOUTFS_MAX_TYPE 16 /* power of 2 is efficient */ -/* value is struct scoutfs_inode */ -struct scoutfs_inode_key { - __u8 zone; - __be64 ino; - __u8 type; -} __packed; - -/* value is struct scoutfs_dirent with the name */ -struct scoutfs_dirent_key { - __u8 zone; - __be64 ino; - __u8 type; - __be64 major; - __be64 minor; -} __packed; - -/* key is bytes of encoded block mapping */ -struct scoutfs_block_mapping_key { - __u8 zone; - __be64 ino; - __u8 type; - __be64 base; -} __packed; - /* each mapping item describes a fixed number of blocks */ #define SCOUTFS_BLOCK_MAPPING_SHIFT 6 #define SCOUTFS_BLOCK_MAPPING_BLOCKS (1 << SCOUTFS_BLOCK_MAPPING_SHIFT) @@ -328,33 +360,10 @@ struct scoutfs_block_mapping_key { #define SCOUTFS_FREE_BITS_U64S \ DIV_ROUND_UP(SCOUTFS_FREE_BITS_BITS, 64) -struct scoutfs_free_bits_key { - __u8 zone; - __be64 node_id; - __u8 type; - __be64 base; -} __packed; - struct scoutfs_free_bits { __le64 bits[SCOUTFS_FREE_BITS_U64S]; } __packed; -struct scoutfs_orphan_key { - __u8 zone; - __be64 node_id; - __u8 type; - __be64 ino; -} __packed; - -struct scoutfs_xattr_key { - __u8 zone; - __be64 ino; - __u8 type; - __be32 name_hash; - __be64 id; - __u8 part; -} __packed; - /* * The first xattr part item has a header that describes the xattr. The * name and value are then packed into the following bytes in the first @@ -366,27 +375,11 @@ struct scoutfs_xattr { __u8 name[0]; } __packed; -/* size determines nr needed to store full target path in their values */ -struct scoutfs_symlink_key { - __u8 zone; - __be64 ino; - __u8 type; - __u8 nr; -} __packed; - struct scoutfs_betimespec { __be64 sec; __be32 nsec; } __packed; -struct scoutfs_inode_index_key { - __u8 zone; - __u8 type; - __be64 major; - __be32 minor; - __be64 ino; -} __packed; - /* XXX does this exist upstream somewhere? */ #define member_sizeof(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER)) @@ -514,9 +507,6 @@ enum { SCOUTFS_DT_WHT, }; -#define SCOUTFS_MAX_KEY_SIZE \ - sizeof(struct scoutfs_dirent_key) - #define SCOUTFS_MAX_VAL_SIZE SCOUTFS_BLOCK_MAPPING_MAX_BYTES #define SCOUTFS_XATTR_MAX_NAME_LEN 255 @@ -591,8 +581,8 @@ struct scoutfs_net_key_range { struct scoutfs_net_manifest_entry { __le64 segno; __le64 seq; - __le16 first_key_len; - __le16 last_key_len; + struct scoutfs_key first; + struct scoutfs_key last; __u8 level; __u8 keys[0]; } __packed; diff --git a/utils/src/ioctl.h b/utils/src/ioctl.h index 721f1cde..915a130b 100644 --- a/utils/src/ioctl.h +++ b/utils/src/ioctl.h @@ -208,11 +208,16 @@ struct scoutfs_ioctl_stat_more { #define SCOUTFS_IOC_STAT_MORE _IOW(SCOUTFS_IOCTL_MAGIC, 7, \ struct scoutfs_ioctl_stat_more) +/* + * Fills the buffer with either the keys for the cached items or the + * keys for the cached ranges found starting with the given key. The + * number of keys filled in the buffer is returned. When filling range + * keys the returned number will always be a multiple of two. + */ struct scoutfs_ioctl_item_cache_keys { - __u64 key_ptr; - __u64 key_len; + struct scoutfs_key key; __u64 buf_ptr; - __u64 buf_len; + __u16 buf_nr; __u8 which; } __packed; diff --git a/utils/src/item-cache-keys.c b/utils/src/item-cache-keys.c index 704a8cc4..68ca48c5 100644 --- a/utils/src/item-cache-keys.c +++ b/utils/src/item-cache-keys.c @@ -16,47 +16,32 @@ #include "cmd.h" #include "key.h" -#define BUF_SIZE (64 * 1024) - static int item_cache_keys(int argc, char **argv, int which) { struct scoutfs_ioctl_item_cache_keys ick; - unsigned nr; - u16 key_len; - void *buf; - void *ptr; + struct scoutfs_key keys[32]; int ret; int fd; + int i; if (argc != 2) { fprintf(stderr, "too many arguments, only scoutfs path needed"); return -EINVAL; } - buf = malloc(BUF_SIZE); - if (!buf) { - ret = -errno; - fprintf(stderr, "failed to allocate buf: %s (%d)\n", - strerror(errno), errno); - return ret; - } - fd = open(argv[1], O_RDONLY); if (fd < 0) { ret = -errno; fprintf(stderr, "failed to open '%s': %s (%d)\n", argv[1], strerror(errno), errno); - free(buf); return ret; } - ick.buf_ptr = (unsigned long)buf; - ick.buf_len = BUF_SIZE; - ick.key_ptr = 0; - ick.key_len = 0; + memset(&ick, 0, sizeof(ick)); + ick.buf_ptr = (unsigned long)keys; + ick.buf_nr = array_size(keys); ick.which = which; - nr = 1; for (;;) { ret = ioctl(fd, SCOUTFS_IOC_ITEM_CACHE_KEYS, &ick); if (ret < 0) { @@ -68,47 +53,21 @@ static int item_cache_keys(int argc, char **argv, int which) break; } - ptr = (void *)(unsigned long)ick.buf_ptr; + for (i = 0; i < ret; i++) { + printf(SK_FMT, SK_ARG(&keys[i])); - while (ret) { - if (ret < sizeof(key_len)) { - fprintf(stderr, "truncated len: %d\n", ret); - ret = -EINVAL; - break; - } - - memcpy(&key_len, ptr, sizeof(key_len)); - ptr += sizeof(key_len); - ret -= sizeof(key_len); - - if (ret < key_len) { - fprintf(stderr, "key len %d < buffer %d\n", - key_len, ret); - ret = -EINVAL; - break; - } - - print_key(ptr, key_len); if (which == SCOUTFS_IOC_ITEM_CACHE_KEYS_ITEMS || - (nr % 2) == 0) + (i & 1)) printf("\n"); else printf(" - "); - - ick.key_ptr = (unsigned long)ptr; - ick.key_len = key_len; - - ptr += key_len; - ret -= key_len; - - nr++; } - if (ret < 0) - break; + + ick.key = keys[i - 1]; + scoutfs_key_inc(&ick.key); } close(fd); - free(buf); return ret; }; diff --git a/utils/src/key.c b/utils/src/key.c index a32f4442..b19b6cd0 100644 --- a/utils/src/key.c +++ b/utils/src/key.c @@ -1,349 +1,55 @@ -#include +/* + * Copyright (C) 2018 Versity Software, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ #include -#include -#include -#include +#include +#include #include "sparse.h" #include "util.h" #include "format.h" #include "key.h" -/* - * To print keys we wrap the key snprintf code from the kernel with a - * few support functions. We need a few functions that the kernel has - * that we don't provide, then we implement our printing function by - * allocating a buffer for the formatted output then just printing it. - * - * To update the key printing code from the kernel we just need to make - * scoutfs_key_str_size() static and replace the snprintf call with the - * kernel's "%phN" format with the call to our replacement. - * - * This is not efficient but this isn't a performant path. - */ - -#define min_t(t, a, b) min(a, b) - -struct scoutfs_key_buf { - void *data; - unsigned key_len; +char *scoutfs_zone_strings[SCOUTFS_MAX_ZONE] = { + [SCOUTFS_INODE_INDEX_ZONE] = "ind", + [SCOUTFS_NODE_ZONE] = "nod", + [SCOUTFS_FS_ZONE] = "fs", }; -/* - * like snprintf(buf, size, "%*phN", nr, bytes) in the kernel, but this - * is only called when there's room for the formatted output because - * we've already been through once with a 0 buffer to allocate a buffer - * for the output. - */ -static int snprintf_phN(char *buf, size_t size, unsigned nr, char *bytes) +char *scoutfs_type_strings[SCOUTFS_MAX_ZONE][SCOUTFS_MAX_TYPE] = { + [SCOUTFS_INODE_INDEX_ZONE][SCOUTFS_INODE_INDEX_META_SEQ_TYPE] = "msq", + [SCOUTFS_INODE_INDEX_ZONE][SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE] = "dsq", + [SCOUTFS_NODE_ZONE][SCOUTFS_FREE_BITS_SEGNO_TYPE] = "fsg", + [SCOUTFS_NODE_ZONE][SCOUTFS_FREE_BITS_BLKNO_TYPE] = "fbk", + [SCOUTFS_NODE_ZONE][SCOUTFS_ORPHAN_TYPE] = "orp", + [SCOUTFS_FS_ZONE][SCOUTFS_INODE_TYPE] = "ino", + [SCOUTFS_FS_ZONE][SCOUTFS_XATTR_TYPE] = "xat", + [SCOUTFS_FS_ZONE][SCOUTFS_DIRENT_TYPE] = "dnt", + [SCOUTFS_FS_ZONE][SCOUTFS_READDIR_TYPE] = "rdr", + [SCOUTFS_FS_ZONE][SCOUTFS_LINK_BACKREF_TYPE] = "lbr", + [SCOUTFS_FS_ZONE][SCOUTFS_SYMLINK_TYPE] = "sym", + [SCOUTFS_FS_ZONE][SCOUTFS_BLOCK_MAPPING_TYPE] = "bmp", +}; + +char scoutfs_unknown_u8_strings[U8_MAX][U8_STR_MAX]; + +static void __attribute__((constructor)) scoutfs_key_init(void) { - int ret = 0; + int ret; int i; - for (i = 0; i < nr; i++) - ret += sprintf(buf + ret, "%02x", bytes[i]); - - return ret; -} - -static char *memchr_inv(char *str, int c, size_t len) -{ - while (len--) { - if (*(str++) != c) - return str - 1; - } - - return NULL; -} - -static int scoutfs_key_str_size(char *buf, struct scoutfs_key_buf *key, - size_t size); - -void print_key(void *key_data, unsigned key_len) -{ - struct scoutfs_key_buf key = {.data = key_data, .key_len = key_len}; - char *buf; - int size; - - size = scoutfs_key_str_size(NULL, &key, 0); - if (size > 0) { - buf = malloc(size); - if (buf) { - size = scoutfs_key_str_size(buf, &key, size); - if (size > 0) - printf("%s", buf); - free(buf); - } + for (i = 0; i <= U8_MAX; i++) { + ret = snprintf(scoutfs_unknown_u8_strings[i], U8_STR_MAX, + "u%u", i); + assert(ret > 0 && ret < U8_STR_MAX); } } - -/* ------ copied code follows --------- */ - -#define snprintf_null(buf, size, fmt, args...) \ - (snprintf((buf), (size), fmt, ##args) + 1) - -/* - * Store a formatted string representing the key in the buffer. The key - * must be at least min_len to store the data needed by the format at - * all. fmt_len is the length of data that's used by the format. These - * are different because we have badly designed keys with variable - * length data that isn't described by the key. It's assumed from the - * length of the key. Take dirents -- they need to at least have a - * dirent struct, but the name length is the rest of the key. - * - * (XXX And this goes horribly wrong when we pad out dirent keys to max - * len to increment at high precision. We'll never see these items used - * by real fs code, but temporary keys and range endpoints can be full - * precision and we can try and print them and get very confused. We - * need to rev the format to include explicit lengths.) - * - * If the format doesn't cover the entire key then we append more - * formatting to represent the trailing bytes: runs of zeros compresesd - * to _ and then hex output of non-zero bytes. - */ -static int snprintf_key(char *buf, size_t size, struct scoutfs_key_buf *key, - unsigned min_len, unsigned fmt_len, - const char *fmt, ...) - -{ - va_list args; - char *data; - char *end; - int left; - int part; - int ret; - int nr; - - if (key->key_len < min_len) - return snprintf_null(buf, size, "[trunc len %u < min %u]", - key->key_len, min_len); - - if (fmt_len == 0) - fmt_len = min_len; - - va_start(args, fmt); - ret = vsnprintf(buf, size, fmt, args); - va_end(args); - /* next formatting overwrites null */ - if (buf) { - buf += ret; - size -= min_t(int, size, ret); - } - - data = key->data + fmt_len; - left = key->key_len - fmt_len; - - while (left && (!buf || size > 1)) { - /* compress runs of zero bytes to _ */ - end = memchr_inv(data, 0, left); - nr = end ? end - data : left; - if (nr) { - if (buf) { - *(buf++) = '_'; - size--; - } - ret++; - data += nr; - left -= nr; - continue; - } - - /* - * hex print non-zero bytes. %ph is limited to 64 bytes - * and is buggy in that it still tries to print to buf - * past size. (so buf = null, size = 0 crashes instead - * of printing the length of the formatted string.) - */ - end = memchr(data, 0, left); - nr = end ? end - data : left; - nr = min(nr, 64); - - if (buf) - part = snprintf_phN(buf, size, nr, data); - else - part = nr * 2; - if (buf) { - buf += part; - size -= min_t(int, size, part); - } - ret += part; - - data += nr; - left -= nr; - } - - /* always store and include null */ - if (buf) - *buf = '\0'; - return ret + 1; -} - -typedef int (*key_printer_t)(char *buf, struct scoutfs_key_buf *key, - size_t size); - -static int pr_ino_idx(char *buf, struct scoutfs_key_buf *key, size_t size) -{ - static char *type_strings[] = { - [SCOUTFS_INODE_INDEX_META_SEQ_TYPE] = "msq", - [SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE] = "dsq", - }; - struct scoutfs_inode_index_key *ikey = key->data; - - return snprintf_key(buf, size, key, - sizeof(struct scoutfs_inode_index_key), 0, - "iin.%s.%llu.%u.%llu", - type_strings[ikey->type], be64_to_cpu(ikey->major), - be32_to_cpu(ikey->minor), be64_to_cpu(ikey->ino)); -} - -static int pr_free_bits(char *buf, struct scoutfs_key_buf *key, size_t size) -{ - static char *type_strings[] = { - [SCOUTFS_FREE_BITS_SEGNO_TYPE] = "fsg", - [SCOUTFS_FREE_BITS_BLKNO_TYPE] = "fbk", - }; - struct scoutfs_free_bits_key *frk = key->data; - - return snprintf_key(buf, size, key, - sizeof(struct scoutfs_block_mapping_key), 0, - "nod.%llu.%s.%llu", - be64_to_cpu(frk->node_id), - type_strings[frk->type], - be64_to_cpu(frk->base)); -} - -static int pr_orphan(char *buf, struct scoutfs_key_buf *key, size_t size) -{ - struct scoutfs_orphan_key *okey = key->data; - - return snprintf_key(buf, size, key, - sizeof(struct scoutfs_orphan_key), 0, - "nod.%llu.orp.%llu", - be64_to_cpu(okey->node_id), - be64_to_cpu(okey->ino)); -} - -static int pr_inode(char *buf, struct scoutfs_key_buf *key, size_t size) -{ - struct scoutfs_inode_key *ikey = key->data; - - return snprintf_key(buf, size, key, - sizeof(struct scoutfs_inode_key), 0, - "fs.%llu.ino", - be64_to_cpu(ikey->ino)); -} - -static int pr_xattr(char *buf, struct scoutfs_key_buf *key, size_t size) -{ - struct scoutfs_xattr_key *xkey = key->data; - - return snprintf_key(buf, size, key, - sizeof(struct scoutfs_xattr_key), key->key_len, - "fs.%llu.xat.%08x.%llu.%u", - be64_to_cpu(xkey->ino), - be32_to_cpu(xkey->name_hash), - be64_to_cpu(xkey->id), xkey->part); -} - -static int pr_dirent(char *buf, struct scoutfs_key_buf *key, size_t size) -{ - struct scoutfs_dirent_key *dkey = key->data; - char *which = dkey->type == SCOUTFS_DIRENT_TYPE ? "dnt" : - dkey->type == SCOUTFS_READDIR_TYPE ? "rdr" : - dkey->type == SCOUTFS_LINK_BACKREF_TYPE ? "lbr" : - "unk"; - - return snprintf_key(buf, size, key, - sizeof(struct scoutfs_dirent_key), key->key_len, - "fs.%llu.%s.%llu.%llu", - be64_to_cpu(dkey->ino), which, - be64_to_cpu(dkey->major), - be64_to_cpu(dkey->minor)); -} - -static int pr_symlink(char *buf, struct scoutfs_key_buf *key, size_t size) -{ - struct scoutfs_symlink_key *skey = key->data; - - return snprintf_key(buf, size, key, - sizeof(struct scoutfs_symlink_key), 0, - "fs.%llu.sym", - be64_to_cpu(skey->ino)); -} - -static int pr_block_mapping(char *buf, struct scoutfs_key_buf *key, size_t size) -{ - struct scoutfs_block_mapping_key *bmk = key->data; - - return snprintf_key(buf, size, key, - sizeof(struct scoutfs_block_mapping_key), 0, - "fs.%llu.bmp.%llu", - be64_to_cpu(bmk->ino), - be64_to_cpu(bmk->base)); -} - -const static key_printer_t key_printers[SCOUTFS_MAX_ZONE][SCOUTFS_MAX_TYPE] = { - [SCOUTFS_INODE_INDEX_ZONE][SCOUTFS_INODE_INDEX_META_SEQ_TYPE] = - pr_ino_idx, - [SCOUTFS_INODE_INDEX_ZONE][SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE] = - pr_ino_idx, - [SCOUTFS_NODE_ZONE][SCOUTFS_FREE_BITS_SEGNO_TYPE] = pr_free_bits, - [SCOUTFS_NODE_ZONE][SCOUTFS_FREE_BITS_BLKNO_TYPE] = pr_free_bits, - [SCOUTFS_NODE_ZONE][SCOUTFS_ORPHAN_TYPE] = pr_orphan, - [SCOUTFS_FS_ZONE][SCOUTFS_INODE_TYPE] = pr_inode, - [SCOUTFS_FS_ZONE][SCOUTFS_XATTR_TYPE] = pr_xattr, - [SCOUTFS_FS_ZONE][SCOUTFS_DIRENT_TYPE] = pr_dirent, - [SCOUTFS_FS_ZONE][SCOUTFS_READDIR_TYPE] = pr_dirent, - [SCOUTFS_FS_ZONE][SCOUTFS_LINK_BACKREF_TYPE] = pr_dirent, - [SCOUTFS_FS_ZONE][SCOUTFS_SYMLINK_TYPE] = pr_symlink, - [SCOUTFS_FS_ZONE][SCOUTFS_BLOCK_MAPPING_TYPE] = pr_block_mapping, -}; - -/* - * Write the null-terminated string that describes the key to the - * buffer. The bytes copied (including the null) is returned. A null - * buffer can be used to find the string size without writing anything. - * - * XXX nonprintable characters in the trace? - */ -static int scoutfs_key_str_size(char *buf, struct scoutfs_key_buf *key, - size_t size) -{ - u8 zone; - u8 type; - - if (key == NULL || key->data == NULL) - return snprintf_null(buf, size, "[NULL]"); - - /* always at least zone, some id, and type */ - if (key->key_len < (1 + 8 + 1)) - return snprintf_null(buf, size, "[trunc len %u]", key->key_len); - - zone = *(u8 *)key->data; - - /* - * each zone's keys always start with the same fields that let - * us deref any key to get the type. We chose a few representative - * keys from each zone to get the type. - */ - if (zone == SCOUTFS_INODE_INDEX_ZONE) { - struct scoutfs_inode_index_key *ikey = key->data; - type = ikey->type; - } else if (zone == SCOUTFS_NODE_ZONE) { - struct scoutfs_free_bits_key *fbk = key->data; - type = fbk->type; - } else if (zone == SCOUTFS_FS_ZONE) { - struct scoutfs_inode_key *ikey = key->data; - type = ikey->type; - } else { - type = 255; - } - - if (zone > SCOUTFS_MAX_ZONE || type > SCOUTFS_MAX_TYPE || - key_printers[zone][type] == NULL) { - return snprintf_null(buf, size, "[unk zone %u type %u]", - zone, type); - } - - return key_printers[zone][type](buf, key, size); -} diff --git a/utils/src/key.h b/utils/src/key.h index bb51b80f..9401286f 100644 --- a/utils/src/key.h +++ b/utils/src/key.h @@ -1,6 +1,172 @@ -#ifndef _KEY_H_ -#define _KEY_H_ +#ifndef _SCOUTFS_KEY_H_ +#define _SCOUTFS_KEY_H_ -void print_key(void *key_data, unsigned key_len); +#include "sparse.h" +#include "util.h" +#include "format.h" +#include "cmp.h" +#include "endian_swap.h" + +extern char *scoutfs_zone_strings[SCOUTFS_MAX_ZONE]; +extern char *scoutfs_type_strings[SCOUTFS_MAX_ZONE][SCOUTFS_MAX_TYPE]; +#define U8_STR_MAX 5 /* u%3u'\0' */ +extern char scoutfs_unknown_u8_strings[U8_MAX][U8_STR_MAX]; + +static inline char *sk_zone_str(u8 zone) +{ + if (zone >= SCOUTFS_MAX_ZONE || scoutfs_zone_strings[zone] == NULL) + return scoutfs_unknown_u8_strings[zone]; + + return scoutfs_zone_strings[zone]; +} + +static inline char *sk_type_str(u8 zone, u8 type) +{ + if (zone >= SCOUTFS_MAX_ZONE || type >= SCOUTFS_MAX_TYPE || + scoutfs_type_strings[zone][type] == NULL) + return scoutfs_unknown_u8_strings[type]; + + return scoutfs_type_strings[zone][type]; +} + +#define SK_FMT "%s.%llu.%s.%llu.%llu.%u" +/* This does not support null keys */ +#define SK_ARG(key) sk_zone_str((key)->sk_zone), \ + le64_to_cpu((key)->_sk_first), \ + sk_type_str((key)->sk_zone, (key)->sk_type), \ + le64_to_cpu((key)->_sk_second), \ + le64_to_cpu((key)->_sk_third), \ + (key)->_sk_fourth + +static inline void scoutfs_key_set_zeros(struct scoutfs_key *key) +{ + key->sk_zone = 0; + key->_sk_first = 0; + key->sk_type = 0; + key->_sk_second = 0; + key->_sk_third = 0; + key->_sk_fourth = 0; +} + +static inline void scoutfs_key_copy_or_zeros(struct scoutfs_key *dst, + struct scoutfs_key *src) +{ + if (src) + *dst = *src; + else + scoutfs_key_set_zeros(dst); +} + +static inline void scoutfs_key_set_ones(struct scoutfs_key *key) +{ + key->sk_zone = U8_MAX; + key->_sk_first = cpu_to_le64(U64_MAX); + key->sk_type = U8_MAX; + key->_sk_second = cpu_to_le64(U64_MAX); + key->_sk_third = cpu_to_le64(U64_MAX); + key->_sk_fourth = U8_MAX; +} + +/* + * Return a -1/0/1 comparison of keys. + * + * It turns out that these ternary chains are consistently cheaper than + * other alternatives across keys that first differ in any of the + * values. Say maybe 20% faster than memcmp. + */ +static inline int scoutfs_key_compare(struct scoutfs_key *a, + struct scoutfs_key *b) +{ + return scoutfs_cmp(a->sk_zone, b->sk_zone) ?: + scoutfs_cmp(le64_to_cpu(a->_sk_first), le64_to_cpu(b->_sk_first)) ?: + scoutfs_cmp(a->sk_type, b->sk_type) ?: + scoutfs_cmp(le64_to_cpu(a->_sk_second), le64_to_cpu(b->_sk_second)) ?: + scoutfs_cmp(le64_to_cpu(a->_sk_third), le64_to_cpu(b->_sk_third)) ?: + scoutfs_cmp(a->_sk_fourth, b->_sk_fourth); +} + +/* + * Compare ranges of keys where overlapping is equality. Returns: + * -1: a_end < b_start + * 1: a_start > b_end + * else 0: ranges overlap + */ +static inline int scoutfs_key_compare_ranges(struct scoutfs_key *a_start, + struct scoutfs_key *a_end, + struct scoutfs_key *b_start, + struct scoutfs_key *b_end) +{ + return scoutfs_key_compare(a_end, b_start) < 0 ? -1 : + scoutfs_key_compare(a_start, b_end) > 0 ? 1 : + 0; +} + +static inline void scoutfs_key_inc(struct scoutfs_key *key) +{ + if (++key->_sk_fourth != 0) + return; + + le64_add_cpu(&key->_sk_third, 1); + if (key->_sk_third != 0) + return; + + le64_add_cpu(&key->_sk_second, 1); + if (key->_sk_second != 0) + return; + + if (++key->sk_type != 0) + return; + + le64_add_cpu(&key->_sk_first, 1); + if (key->_sk_first != 0) + return; + + key->sk_zone++; +} + +static inline void scoutfs_key_dec(struct scoutfs_key *key) +{ + if (--key->_sk_fourth != U8_MAX) + return; + + le64_add_cpu(&key->_sk_third, -1); + if (key->_sk_third != cpu_to_le64(U64_MAX)) + return; + + le64_add_cpu(&key->_sk_second, -1); + if (key->_sk_second != cpu_to_le64(U64_MAX)) + return; + + if (--key->sk_type != U8_MAX) + return; + + le64_add_cpu(&key->_sk_first, -1); + if (key->_sk_first != cpu_to_le64(U64_MAX)) + return; + + key->sk_zone--; +} + +static inline void scoutfs_key_to_be(struct scoutfs_key_be *be, + struct scoutfs_key *key) +{ + be->sk_zone = key->sk_zone; + be->_sk_first = le64_to_be64(key->_sk_first); + be->sk_type = key->sk_type; + be->_sk_second = le64_to_be64(key->_sk_second); + be->_sk_third = le64_to_be64(key->_sk_third); + be->_sk_fourth = key->_sk_fourth; +} + +static inline void scoutfs_key_from_be(struct scoutfs_key *key, + struct scoutfs_key_be *be) +{ + key->sk_zone = be->sk_zone; + key->_sk_first = be64_to_le64(be->_sk_first); + key->sk_type = be->sk_type; + key->_sk_second = be64_to_le64(be->_sk_second); + key->_sk_third = be64_to_le64(be->_sk_third); + key->_sk_fourth = be->_sk_fourth; +} #endif diff --git a/utils/src/mkfs.c b/utils/src/mkfs.c index 96497e47..4b357487 100644 --- a/utils/src/mkfs.c +++ b/utils/src/mkfs.c @@ -17,6 +17,7 @@ #include "crc.h" #include "rand.h" #include "dev.h" +#include "key.h" static int write_raw_block(int fd, u64 blkno, void *blk) { @@ -107,10 +108,8 @@ static u64 calc_btree_ring_blocks(u64 total_segs) sizeof(struct scoutfs_alloc_region_btree_val)); blocks += calc_btree_blocks(total_segs, - sizeof(struct scoutfs_manifest_btree_key) + - SCOUTFS_MAX_KEY_SIZE, - sizeof(struct scoutfs_manifest_btree_val) + - SCOUTFS_MAX_KEY_SIZE); + sizeof(struct scoutfs_manifest_btree_key), + sizeof(struct scoutfs_manifest_btree_val)); return round_up(blocks * 4, SCOUTFS_SEGMENT_BLOCKS); } @@ -153,8 +152,8 @@ static char *size_str(u64 nr, unsigned size) static int write_new_fs(char *path, int fd) { struct scoutfs_super_block *super; - struct scoutfs_inode_key *ikey; - struct scoutfs_inode_index_key *idx_key; + struct scoutfs_key *ino_key; + struct scoutfs_key *idx_key; struct scoutfs_inode *inode; struct scoutfs_segment_block *sblk; struct scoutfs_manifest_btree_key *mkey; @@ -162,6 +161,7 @@ static int write_new_fs(char *path, int fd) struct scoutfs_btree_block *bt; struct scoutfs_btree_item *btitem; struct scoutfs_segment_item *item; + struct scoutfs_key key; __le32 *prev_link; struct timeval tv; char uuid_str[37]; @@ -245,34 +245,29 @@ static int write_new_fs(char *path, int fd) bt->nr_items = cpu_to_le16(1); /* btree item allocated from the back of the block */ - ikey = (void *)bt + SCOUTFS_BLOCK_SIZE - sizeof(*ikey); - mval = (void *)ikey - sizeof(*mval); - idx_key = (void *)mval - sizeof(*idx_key); - mkey = (void *)idx_key - sizeof(*mkey); + mval = (void *)bt + SCOUTFS_BLOCK_SIZE - sizeof(*mval); + ino_key = &mval->last_key; + mkey = (void *)mval - sizeof(*mkey); btitem = (void *)mkey - sizeof(*btitem); bt->item_hdrs[0].off = cpu_to_le16((long)btitem - (long)bt); bt->free_end = bt->item_hdrs[0].off; - btitem->key_len = cpu_to_le16(sizeof(struct scoutfs_manifest_btree_key) + - sizeof(struct scoutfs_inode_index_key)); - btitem->val_len = cpu_to_le16(sizeof(struct scoutfs_manifest_btree_val) + - sizeof(struct scoutfs_inode_key)); + btitem->key_len = cpu_to_le16(sizeof(*mkey)); + btitem->val_len = cpu_to_le16(sizeof(*mval)); mkey->level = 1; - idx_key->zone = SCOUTFS_INODE_INDEX_ZONE; - idx_key->type = SCOUTFS_INODE_INDEX_META_SEQ_TYPE; - idx_key->major = 0; - idx_key->minor = 0; - idx_key->ino = cpu_to_be64(SCOUTFS_ROOT_INO); + mkey->seq = cpu_to_be64(1); + memset(&key, 0, sizeof(key)); + key.sk_zone = SCOUTFS_INODE_INDEX_ZONE; + key.sk_type = SCOUTFS_INODE_INDEX_META_SEQ_TYPE; + key.skii_ino = cpu_to_le64(SCOUTFS_ROOT_INO); + scoutfs_key_to_be(&mkey->first_key, &key); mval->segno = cpu_to_le64(first_segno); - mval->seq = cpu_to_le64(1); - mval->first_key_len = cpu_to_le16(sizeof(struct scoutfs_inode_index_key)); - mval->last_key_len = cpu_to_le16(sizeof(struct scoutfs_inode_key)); - ikey->zone = SCOUTFS_FS_ZONE; - ikey->ino = cpu_to_be64(SCOUTFS_ROOT_INO); - ikey->type = SCOUTFS_INODE_TYPE; + ino_key->sk_zone = SCOUTFS_FS_ZONE; + ino_key->ski_ino = cpu_to_le64(SCOUTFS_ROOT_INO); + ino_key->sk_type = SCOUTFS_INODE_TYPE; bt->crc = cpu_to_le32(crc_btree_block(bt)); @@ -294,35 +289,31 @@ static int write_new_fs(char *path, int fd) *prev_link = cpu_to_le32((long)item -(long)sblk); prev_link = &item->skip_links[0]; - item->key_len = cpu_to_le16(sizeof(*idx_key)); item->val_len = 0; item->nr_links = 1; le32_add_cpu(&sblk->nr_items, 1); - idx_key = (void *)&item->skip_links[1]; - idx_key->zone = SCOUTFS_INODE_INDEX_ZONE; - idx_key->type = SCOUTFS_INODE_INDEX_META_SEQ_TYPE; - idx_key->ino = cpu_to_be64(SCOUTFS_ROOT_INO); - idx_key->major = 0; - idx_key->minor = 0; + idx_key = &item->key; + idx_key->sk_zone = SCOUTFS_INODE_INDEX_ZONE; + idx_key->sk_type = SCOUTFS_INODE_INDEX_META_SEQ_TYPE; + idx_key->skii_ino = cpu_to_le64(SCOUTFS_ROOT_INO); - item = (void *)(idx_key + 1); + item = (void *)&item->skip_links[1]; *prev_link = cpu_to_le32((long)item -(long)sblk); prev_link = &item->skip_links[0]; sblk->last_item_off = cpu_to_le32((long)item - (long)sblk); - ikey = (void *)&item->skip_links[1]; - inode = (void *)ikey + sizeof(struct scoutfs_inode_key); + ino_key = (void *)&item->key; + inode = (void *)&item->skip_links[1]; - item->key_len = cpu_to_le16(sizeof(struct scoutfs_inode_key)); item->val_len = cpu_to_le16(sizeof(struct scoutfs_inode)); item->nr_links = 1; le32_add_cpu(&sblk->nr_items, 1); - ikey->zone = SCOUTFS_FS_ZONE; - ikey->ino = cpu_to_be64(SCOUTFS_ROOT_INO); - ikey->type = SCOUTFS_INODE_TYPE; + ino_key->sk_zone = SCOUTFS_FS_ZONE; + ino_key->ski_ino = cpu_to_le64(SCOUTFS_ROOT_INO); + ino_key->sk_type = SCOUTFS_INODE_TYPE; inode->next_readdir_pos = cpu_to_le64(2); inode->nlink = cpu_to_le32(SCOUTFS_DIRENT_FIRST_POS); diff --git a/utils/src/print.c b/utils/src/print.c index a53963fa..02e125e5 100644 --- a/utils/src/print.c +++ b/utils/src/print.c @@ -74,9 +74,8 @@ static void print_block_header(struct scoutfs_block_header *hdr) le64_to_cpu(hdr->seq), le64_to_cpu(hdr->blkno)); } -static void print_inode(void *key, int key_len, void *val, int val_len) +static void print_inode(struct scoutfs_key *key, void *val, int val_len) { - struct scoutfs_inode_key *ikey = key; struct scoutfs_inode *inode = val; printf(" inode: ino %llu size %llu nlink %u\n" @@ -84,7 +83,7 @@ static void print_inode(void *key, int key_len, void *val, int val_len) " next_readdir_pos %llu meta_seq %llu data_seq %llu data_version %llu\n" " atime %llu.%08u ctime %llu.%08u\n" " mtime %llu.%08u\n", - be64_to_cpu(ikey->ino), + le64_to_cpu(key->ski_ino), le64_to_cpu(inode->size), le32_to_cpu(inode->nlink), le32_to_cpu(inode->uid), le32_to_cpu(inode->gid), le32_to_cpu(inode->mode), @@ -102,11 +101,9 @@ static void print_inode(void *key, int key_len, void *val, int val_len) le32_to_cpu(inode->mtime.nsec)); } -static void print_orphan(void *key, int key_len, void *val, int val_len) +static void print_orphan(struct scoutfs_key *key, void *val, int val_len) { - struct scoutfs_orphan_key *okey = key; - - printf(" orphan: ino %llu\n", be64_to_cpu(okey->ino)); + printf(" orphan: ino %llu\n", le64_to_cpu(key->sko_ino)); } static u8 *global_printable_name(u8 *name, int name_len) @@ -122,38 +119,35 @@ static u8 *global_printable_name(u8 *name, int name_len) return name_buf; } -static void print_xattr(void *key, int key_len, void *val, int val_len) +static void print_xattr(struct scoutfs_key *key, void *val, int val_len) { - struct scoutfs_xattr_key *xkey = key; struct scoutfs_xattr *xat = val; printf(" xattr: ino %llu name_hash %08x id %llu part %u\n", - be64_to_cpu(xkey->ino), be32_to_cpu(xkey->name_hash), - be64_to_cpu(xkey->id), xkey->part); + le64_to_cpu(key->skx_ino), (u32)le64_to_cpu(key->skx_name_hash), + le64_to_cpu(key->skx_id), key->skx_part); - if (xkey->part == 0) + if (key->skx_part == 0) printf(" name_len %u val_len %u name %s\n", xat->name_len, le16_to_cpu(xat->val_len), global_printable_name(xat->name, xat->name_len)); } -static void print_dirent(void *key, int key_len, void *val, int val_len) +static void print_dirent(struct scoutfs_key *key, void *val, int val_len) { - struct scoutfs_dirent_key *dkey = key; struct scoutfs_dirent *dent = val; unsigned int name_len = val_len - sizeof(*dent); u8 *name = global_printable_name(dent->name, name_len); printf(" dirent: dir %llu hash %016llx pos %llu type %u ino %llu\n" " name %s\n", - be64_to_cpu(dkey->ino), le64_to_cpu(dent->hash), + le64_to_cpu(key->skd_ino), le64_to_cpu(dent->hash), le64_to_cpu(dent->pos), dent->type, le64_to_cpu(dent->ino), name); } -static void print_symlink(void *key, int key_len, void *val, int val_len) +static void print_symlink(struct scoutfs_key *key, void *val, int val_len) { - struct scoutfs_symlink_key *skey = key; u8 *frag = val; u8 *name; @@ -162,32 +156,30 @@ static void print_symlink(void *key, int key_len, void *val, int val_len) val_len--; name = global_printable_name(frag, val_len); - printf(" symlink: ino %llu nr %u\n" + printf(" symlink: ino %llu nr %llu\n" " target %s\n", - be64_to_cpu(skey->ino), skey->nr, name); + le64_to_cpu(key->sks_ino), le64_to_cpu(key->sks_nr), name); } /* * XXX not decoding the bytes yet */ -static void print_block_mapping(void *key, int key_len, void *val, int val_len) +static void print_block_mapping(struct scoutfs_key *key, void *val, int val_len) { - struct scoutfs_block_mapping_key *bmk = key; - u64 blk_off = be64_to_cpu(bmk->base) << SCOUTFS_BLOCK_MAPPING_SHIFT; + u64 blk_off = le64_to_cpu(key->skm_base) << SCOUTFS_BLOCK_MAPPING_SHIFT; u8 nr = *((u8 *)val) & 63; printf(" block mapping: ino %llu blk_off %llu blocks %u\n", - be64_to_cpu(bmk->ino), blk_off, nr); + le64_to_cpu(key->skm_ino), blk_off, nr); } -static void print_free_bits(void *key, int key_len, void *val, int val_len) +static void print_free_bits(struct scoutfs_key *key, void *val, int val_len) { - struct scoutfs_free_bits_key *fbk = key; struct scoutfs_free_bits *frb = val; int i; printf(" node_id %llx base %llu\n", - be64_to_cpu(fbk->node_id), be64_to_cpu(fbk->base)); + le64_to_cpu(key->skf_node_id), le64_to_cpu(key->skf_base)); printf(" bits:"); for (i = 0; i < array_size(frb->bits); i++) @@ -195,16 +187,13 @@ static void print_free_bits(void *key, int key_len, void *val, int val_len) printf("\n"); } -static void print_inode_index(void *key, int key_len, void *val, int val_len) +static void print_inode_index(struct scoutfs_key *key, 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)); + printf(" index: major %llu ino %llu\n", + le64_to_cpu(key->skii_major), le64_to_cpu(key->skii_ino)); } -typedef void (*print_func_t)(void *key, int key_len, void *val, int val_len); +typedef void (*print_func_t)(struct scoutfs_key *key, void *val, int val_len); static print_func_t find_printer(u8 zone, u8 type) { @@ -237,59 +226,28 @@ static print_func_t find_printer(u8 zone, u8 type) return NULL; } -static void find_zone_type(void *key, u8 *zone, u8 *type) -{ - struct scoutfs_inode_index_key *idx_key = key; - struct scoutfs_inode_key *ikey = key; - struct scoutfs_orphan_key *okey = key; - - *zone = *(u8 *)key; - - switch (*zone) { - case SCOUTFS_INODE_INDEX_ZONE: - *type = idx_key->type; - break; - case SCOUTFS_NODE_ZONE: - *type = okey->type; - break; - case SCOUTFS_FS_ZONE: - *type = ikey->type; - break; - default: - *type = 0; - } -} - static void print_item(struct scoutfs_segment_block *sblk, struct scoutfs_segment_item *item, u32 which, u32 off) { print_func_t printer; - void *key; void *val; - u8 type; - u8 zone; int i; - key = (char *)&item->skip_links[item->nr_links]; - val = (char *)key + le16_to_cpu(item->key_len); + val = (char *)&item->skip_links[item->nr_links]; - find_zone_type(key, &zone, &type); - printer = find_printer(zone, type); + printer = find_printer(item->key.sk_zone, item->key.sk_type); - printf(" [%u]: off %u key_len %u val_len %u nr_links %u flags %x%s\n", - which, off, le16_to_cpu(item->key_len), - le16_to_cpu(item->val_len), item->nr_links, + printf(" [%u]: key "SK_FMT" off %u val_len %u nr_links %u flags %x%s\n", + which, SK_ARG(&item->key), off, le16_to_cpu(item->val_len), + item->nr_links, item->flags, printer ? "" : " (unrecognized zone+type)"); printf(" links:"); for (i = 0; i < item->nr_links; i++) printf(" %u", le32_to_cpu(item->skip_links[i])); - printf("\n key: "); - print_key(key, le16_to_cpu(item->key_len)); printf("\n"); if (printer) - printer(key, le16_to_cpu(item->key_len), - val, le16_to_cpu(item->val_len)); + printer(&item->key, val, le16_to_cpu(item->val_len)); } static void print_segment_block(struct scoutfs_segment_block *sblk) @@ -341,51 +299,22 @@ static int print_manifest_entry(void *key, unsigned key_len, void *val, { struct scoutfs_manifest_btree_key *mkey = key; struct scoutfs_manifest_btree_val *mval = val; + struct scoutfs_key first; unsigned long *seg_map = arg; - unsigned first_len; - unsigned last_len; - void *first; - void *last; - __be64 seq; - /* parent items only have the key */ - if (val == NULL) { - if (mkey->level == 0) { - memcpy(&seq, mkey->bkey, sizeof(seq)); - printf(" level %u seq %llu\n", - mkey->level, be64_to_cpu(seq)); - } else { - printf(" level %u first ", mkey->level); - print_key(mkey->bkey, key_len - sizeof(mkey->level)); - printf("\n"); - } - return 0; + scoutfs_key_from_be(&first, &mkey->first_key); + + printf(" level %u first "SK_FMT" seq %llu\n", + mkey->level, SK_ARG(&first), be64_to_cpu(mkey->seq)); + + /* only items in leaf blocks have values */ + if (val) { + printf(" segno %llu last "SK_FMT"\n", + le64_to_cpu(mval->segno), SK_ARG(&mval->last_key)); + + set_bit(seg_map, le64_to_cpu(mval->segno)); } - /* leaf items print the whole entry */ - first_len = le16_to_cpu(mval->first_key_len); - last_len = le16_to_cpu(mval->last_key_len); - - if (mkey->level == 0) { - first = mval->keys; - last = mval->keys + first_len; - } else { - first = mkey->bkey; - last = mval->keys; - } - - printf(" level %u segno %llu seq %llu first_len %u last_len %u\n", - mkey->level, le64_to_cpu(mval->segno), le64_to_cpu(mval->seq), - first_len, last_len); - - printf(" first "); - print_key(first, first_len); - printf("\n last "); - print_key(last, last_len); - printf("\n"); - - set_bit(seg_map, le64_to_cpu(mval->segno)); - return 0; } @@ -514,7 +443,7 @@ static int print_btree(int fd, struct scoutfs_super_block *super, char *which, static void print_super_block(struct scoutfs_super_block *super, u64 blkno) { char uuid_str[37]; - __le64 *counts; + u64 count; int i; uuid_unparse(super->uuid, uuid_str); @@ -553,10 +482,10 @@ static void print_super_block(struct scoutfs_super_block *super, u64 blkno) le16_to_cpu(super->manifest.root.migration_key_len)); printf(" level_counts:"); - counts = super->manifest.level_counts; for (i = 0; i < SCOUTFS_MANIFEST_MAX_LEVEL; i++) { - if (le64_to_cpu(counts[i])) - printf(" %u: %llu", i, le64_to_cpu(counts[i])); + count = le64_to_cpu(super->manifest.level_counts[i]); + if (count) + printf(" %u: %llu", i, count); } printf("\n"); } diff --git a/utils/src/stage_release.c b/utils/src/stage_release.c index a7ee719d..293f012d 100644 --- a/utils/src/stage_release.c +++ b/utils/src/stage_release.c @@ -11,6 +11,7 @@ #include "sparse.h" #include "util.h" +#include "format.h" #include "ioctl.h" #include "cmd.h"