#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sparse.h" #include "parse.h" #include "util.h" #include "format.h" #include "bitmap.h" #include "cmd.h" #include "crc.h" #include "key.h" #include "avl.h" #include "srch.h" #include "leaf_item_hash.h" static void print_block_header(struct scoutfs_block_header *hdr, int size) { u32 crc = crc_block(hdr, size); char valid_str[40]; if (crc != le32_to_cpu(hdr->crc)) sprintf(valid_str, "(!= %08x) ", crc); else valid_str[0] = '\0'; printf(" hdr: crc %08x %smagic %08x fsid %llx blkno %llu seq %llu\n", le32_to_cpu(hdr->crc), valid_str, le32_to_cpu(hdr->magic), le64_to_cpu(hdr->fsid), le64_to_cpu(hdr->blkno), le64_to_cpu(hdr->seq)); } static void print_inode(struct scoutfs_key *key, void *val, int val_len) { struct scoutfs_inode *inode = val; printf(" inode: ino %llu size %llu nlink %u\n" " uid %u gid %u mode 0%o rdev 0x%x flags 0x%x\n" " 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", 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), le32_to_cpu(inode->rdev), le32_to_cpu(inode->flags), le64_to_cpu(inode->next_readdir_pos), le64_to_cpu(inode->meta_seq), le64_to_cpu(inode->data_seq), le64_to_cpu(inode->data_version), le64_to_cpu(inode->atime.sec), le32_to_cpu(inode->atime.nsec), le64_to_cpu(inode->ctime.sec), le32_to_cpu(inode->ctime.nsec), le64_to_cpu(inode->mtime.sec), le32_to_cpu(inode->mtime.nsec)); } static void print_orphan(struct scoutfs_key *key, void *val, int val_len) { printf(" orphan: ino %llu\n", le64_to_cpu(key->sko_ino)); } static u8 *global_printable_name(u8 *name, int name_len) { static u8 name_buf[SCOUTFS_NAME_LEN + 1]; int i; name_len = min(SCOUTFS_NAME_LEN, name_len); for (i = 0; i < name_len; i++) name_buf[i] = isprint(name[i]) ? name[i] : '.'; name_buf[i] = '\0'; return name_buf; } static void print_xattr(struct scoutfs_key *key, void *val, int val_len) { struct scoutfs_xattr *xat = val; printf(" xattr: ino %llu name_hash %08x id %llu part %u\n", le64_to_cpu(key->skx_ino), (u32)le64_to_cpu(key->skx_name_hash), le64_to_cpu(key->skx_id), key->skx_part); 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(struct scoutfs_key *key, void *val, int val_len) { 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", 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(struct scoutfs_key *key, void *val, int val_len) { u8 *frag = val; u8 *name; /* don't try to print null term */ if (frag[val_len - 1] == '\0') val_len--; name = global_printable_name(frag, val_len); printf(" symlink: ino %llu nr %llu\n" " target %s\n", le64_to_cpu(key->sks_ino), le64_to_cpu(key->sks_nr), name); } static void print_data_extent(struct scoutfs_key *key, void *val, int val_len) { struct scoutfs_data_extent_val *dv = val; u64 iblock; iblock = le64_to_cpu(key->skdx_end) - le64_to_cpu(key->skdx_len) + 1; printf(" extent: ino %llu iblock %llu len %llu blkno %llu flags %x\n", le64_to_cpu(key->skdx_ino), iblock, le64_to_cpu(key->skdx_len), le64_to_cpu(dv->blkno), dv->flags); } static void print_inode_index(struct scoutfs_key *key, void *val, int val_len) { printf(" index: major %llu ino %llu\n", le64_to_cpu(key->skii_major), le64_to_cpu(key->skii_ino)); } typedef void (*print_func_t)(struct scoutfs_key *key, void *val, int val_len); static print_func_t find_printer(u8 zone, u8 type) { if (zone == SCOUTFS_INODE_INDEX_ZONE && type >= SCOUTFS_INODE_INDEX_META_SEQ_TYPE && type <= SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE) return print_inode_index; if (zone == SCOUTFS_RID_ZONE) { if (type == SCOUTFS_ORPHAN_TYPE) return print_orphan; } if (zone == SCOUTFS_FS_ZONE) { switch(type) { case SCOUTFS_INODE_TYPE: return print_inode; case SCOUTFS_XATTR_TYPE: return print_xattr; case SCOUTFS_DIRENT_TYPE: return print_dirent; case SCOUTFS_READDIR_TYPE: return print_dirent; case SCOUTFS_SYMLINK_TYPE: return print_symlink; case SCOUTFS_LINK_BACKREF_TYPE: return print_dirent; case SCOUTFS_DATA_EXTENT_TYPE: return print_data_extent; } } return NULL; } static int print_fs_item(struct scoutfs_key *key, void *val, unsigned val_len, void *arg) { print_func_t printer; printf(" "SK_FMT"\n", SK_ARG(key)); /* only items in leaf blocks have values */ if (val) { printer = find_printer(key->sk_zone, key->sk_type); if (printer) printer(key, val, val_len); else printf(" (unknown zone %u type %u)\n", key->sk_zone, key->sk_type); } return 0; } /* same as fs item but with a small header in the value */ static int print_logs_item(struct scoutfs_key *key, void *val, unsigned val_len, void *arg) { struct scoutfs_log_item_value *liv; print_func_t printer; printf(" "SK_FMT"\n", SK_ARG(key)); /* only items in leaf blocks have values */ if (val) { liv = val; printf(" log_item_value: vers %llu flags %x\n", le64_to_cpu(liv->vers), liv->flags); /* deletion items don't have values */ if (!(liv->flags & SCOUTFS_LOG_ITEM_FLAG_DELETION)) { printer = find_printer(key->sk_zone, key->sk_type); if (printer) printer(key, val + sizeof(*liv), val_len - sizeof(*liv)); else printf(" (unknown zone %u type %u)\n", key->sk_zone, key->sk_type); } } return 0; } #define BTREF_F \ "blkno %llu seq %llu" #define BTREF_A(ref) \ le64_to_cpu((ref)->blkno), le64_to_cpu((ref)->seq) #define BTROOT_F \ BTREF_F" height %u" #define BTROOT_A(root) \ BTREF_A(&(root)->ref), (root)->height #define AL_REF_F \ "blkno %llu seq %llu" #define AL_REF_A(p) \ le64_to_cpu((p)->blkno), le64_to_cpu((p)->seq) #define AL_HEAD_F \ AL_REF_F" total_nr %llu first_nr %u" #define AL_HEAD_A(p) \ AL_REF_A(&(p)->ref), le64_to_cpu((p)->total_nr),\ le32_to_cpu((p)->first_nr) #define ALCROOT_F \ BTROOT_F" total_len %llu" #define ALCROOT_A(ar) \ BTROOT_A(&(ar)->root), le64_to_cpu((ar)->total_len) #define SRE_FMT "%016llx.%llu.%llu" #define SRE_A(sre) \ le64_to_cpu((sre)->hash), le64_to_cpu((sre)->ino), \ le64_to_cpu((sre)->id) #define SRF_FMT \ "f "SRE_FMT" l "SRE_FMT" blks %llu ents %llu hei %u blkno %llu seq %016llx" #define SRF_A(srf) \ SRE_A(&(srf)->first), SRE_A(&(srf)->last), \ le64_to_cpu((srf)->blocks), le64_to_cpu((srf)->entries), \ (srf)->height, le64_to_cpu((srf)->ref.blkno), \ le64_to_cpu((srf)->ref.seq) /* same as fs item but with a small header in the value */ static int print_log_trees_item(struct scoutfs_key *key, void *val, unsigned val_len, void *arg) { struct scoutfs_log_trees *lt = val; printf(" rid %llu nr %llu\n", le64_to_cpu(key->sklt_rid), le64_to_cpu(key->sklt_nr)); /* only items in leaf blocks have values */ if (val) { printf(" meta_avail: "AL_HEAD_F"\n" " meta_freed: "AL_HEAD_F"\n" " item_root: height %u blkno %llu seq %llu\n" " bloom_ref: blkno %llu seq %llu\n" " data_avail: "ALCROOT_F"\n" " data_freed: "ALCROOT_F"\n" " srch_file: "SRF_FMT"\n" " max_item_vers: %llu\n" " rid: %016llx\n" " nr: %llu\n", AL_HEAD_A(<->meta_avail), AL_HEAD_A(<->meta_freed), lt->item_root.height, le64_to_cpu(lt->item_root.ref.blkno), le64_to_cpu(lt->item_root.ref.seq), le64_to_cpu(lt->bloom_ref.blkno), le64_to_cpu(lt->bloom_ref.seq), ALCROOT_A(<->data_avail), ALCROOT_A(<->data_freed), SRF_A(<->srch_file), le64_to_cpu(lt->max_item_vers), le64_to_cpu(lt->rid), le64_to_cpu(lt->nr)); } return 0; } static int print_srch_root_item(struct scoutfs_key *key, void *val, unsigned val_len, void *arg) { struct scoutfs_srch_compact *sc; struct scoutfs_srch_file *sfl; int i; printf(" "SK_FMT"\n", SK_ARG(key)); /* only items in leaf blocks have values */ if (val) { if (key->sk_type == SCOUTFS_SRCH_PENDING_TYPE || key->sk_type == SCOUTFS_SRCH_BUSY_TYPE) { sc = val; printf(" compact %s: nr %u flags 0x%x\n", key->sk_type == SCOUTFS_SRCH_PENDING_TYPE ? "pending" : "busy", sc->nr, sc->flags); for (i = 0; i < sc->nr; i++) { printf(" [%u] blk %llu pos %llu sfl "SRF_FMT"\n", i, le64_to_cpu(sc->in[i].blk), le64_to_cpu(sc->in[i].pos), SRF_A(&sc->in[i].sfl)); } } else { sfl = val; printf(" "SRF_FMT"\n", SRF_A(sfl)); } } return 0; } static int print_trans_seqs_entry(struct scoutfs_key *key, void *val, unsigned val_len, void *arg) { printf(" trans_seq %llu rid %016llx\n", le64_to_cpu(key->skts_trans_seq), le64_to_cpu(key->skts_rid)); return 0; } static int print_mounted_client_entry(struct scoutfs_key *key, void *val, unsigned val_len, void *arg) { struct scoutfs_mounted_client_btree_val *mcv = val; printf(" rid %016llx flags 0x%x\n", le64_to_cpu(key->skmc_rid), mcv->flags); return 0; } static int print_alloc_item(struct scoutfs_key *key, void *val, unsigned val_len, void *arg) { if (key->sk_type == SCOUTFS_FREE_EXTENT_BLKNO_TYPE) printf(" free extent: blkno %llu len %llu end %llu\n", le64_to_cpu(key->skfb_end) - le64_to_cpu(key->skfb_len) + 1, le64_to_cpu(key->skfb_len), le64_to_cpu(key->skfb_end)); else printf(" free extent: blkno %llu len %llu neglen %lld\n", le64_to_cpu(key->skfl_blkno), -le64_to_cpu(key->skfl_neglen), (long long)le64_to_cpu(key->skfl_neglen)); return 0; } typedef int (*print_item_func)(struct scoutfs_key *key, void *val, unsigned val_len, void *arg); static int print_block_ref(struct scoutfs_key *key, void *val, unsigned val_len, print_item_func func, void *arg) { struct scoutfs_block_ref *ref = val; func(key, NULL, 0, arg); printf(" ref blkno %llu seq %llu\n", le64_to_cpu(ref->blkno), le64_to_cpu(ref->seq)); return 0; } static void print_leaf_item_hash(struct scoutfs_btree_block *bt) { __le16 *b; int col; int nr; int i; /* print the leaf item hash */ printf(" item hash: "); col = 13; b = leaf_item_hash_buckets(bt); nr = 0; for (i = 0; i < SCOUTFS_BTREE_LEAF_ITEM_HASH_NR; i++) { if (b[i] == 0) continue; nr++; col += snprintf(NULL, 0, "%u,%u ", i, le16_to_cpu(b[i])); if (col >= 78) { printf("\n "); col = 3; } printf("%u,%u ", i, le16_to_cpu(b[i])); } if (col != 3) printf("\n"); printf(" (%u / %u populated, %u%% load)\n", nr, (int)SCOUTFS_BTREE_LEAF_ITEM_HASH_NR, nr * 100 / (int)SCOUTFS_BTREE_LEAF_ITEM_HASH_NR); } static int print_btree_block(int fd, struct scoutfs_super_block *super, char *which, struct scoutfs_block_ref *ref, print_item_func func, void *arg, u8 level) { struct scoutfs_btree_item *item; struct scoutfs_avl_node *node; struct scoutfs_btree_block *bt; struct scoutfs_key *key; unsigned int val_len; unsigned int off; void *val; int ret; int i; ret = read_block(fd, le64_to_cpu(ref->blkno), SCOUTFS_BLOCK_LG_SHIFT, (void **)&bt); if (ret) return ret; if (bt->level == level) { printf("%s btree blkno %llu\n" " crc %08x fsid %llx seq %llu blkno %llu \n" " total_item_bytes %u mid_free_len %u\n" " level %u nr_items %u item_root.node %u\n", which, le64_to_cpu(ref->blkno), le32_to_cpu(bt->hdr.crc), le64_to_cpu(bt->hdr.fsid), le64_to_cpu(bt->hdr.seq), le64_to_cpu(bt->hdr.blkno), le16_to_cpu(bt->total_item_bytes), le16_to_cpu(bt->mid_free_len), bt->level, le16_to_cpu(bt->nr_items), le16_to_cpu(bt->item_root.node)); if (bt->level == 0) print_leaf_item_hash(bt); } for (i = 0, node = avl_first(&bt->item_root); node; i++, node = avl_next(&bt->item_root, node)) { item = container_of(node, struct scoutfs_btree_item, node); off = (void *)item - (void *)bt; val_len = le16_to_cpu(item->val_len); key = &item->key; val = (void *)bt + le16_to_cpu(item->val_off); if (level < bt->level) { ref = val; /* XXX check len */ if (ref->blkno) { ret = print_btree_block(fd, super, which, ref, func, arg, level); if (ret) break; } continue; } printf(" [%u] off %u par %u l %u r %u h %u vo %u vl %u\n", i, off, le16_to_cpu(item->node.parent), le16_to_cpu(item->node.left), le16_to_cpu(item->node.right), item->node.height, le16_to_cpu(item->val_off), val_len); if (level) print_block_ref(key, val, val_len, func, arg); else func(key, val, val_len, arg); } free(bt); return 0; } /* * We print btrees by a breadth-first search. This way all the parent * blocks are printed before the factor of fanout more numerous leaf * blocks and their included items. */ static int print_btree(int fd, struct scoutfs_super_block *super, char *which, struct scoutfs_btree_root *root, print_item_func func, void *arg) { int ret = 0; int i; for (i = root->height - 1; i >= 0; i--) { ret = print_btree_block(fd, super, which, &root->ref, func, arg, i); if (ret) break; } return ret; } static int print_alloc_list_block(int fd, char *str, struct scoutfs_block_ref *ref) { struct scoutfs_alloc_list_block *lblk; struct scoutfs_block_ref next; u64 blkno; u64 start; u64 len; int wid; int ret; int i; blkno = le64_to_cpu(ref->blkno); if (blkno == 0) return 0; ret = read_block(fd, blkno, SCOUTFS_BLOCK_LG_SHIFT, (void **)&lblk); if (ret) return ret; printf("%s alloc_list_block blkno %llu\n", str, blkno); print_block_header(&lblk->hdr, SCOUTFS_BLOCK_LG_SIZE); printf(" next "AL_REF_F" start %u nr %u\n", AL_REF_A(&lblk->next), le32_to_cpu(lblk->start), le32_to_cpu(lblk->nr)); if (lblk->nr) { wid = printf(" exts: "); start = 0; len = 0; for (i = 0; i < le32_to_cpu(lblk->nr); i++) { if (len == 0) start = le64_to_cpu(lblk->blknos[i]); len++; if (i == (le32_to_cpu(lblk->nr) - 1) || start + len != le64_to_cpu(lblk->blknos[i + 1])) { if (wid >= 72) wid = printf("\n "); wid += printf("%llu,%llu ", start, len); len = 0; } } printf("\n"); } next = lblk->next; free(lblk); return print_alloc_list_block(fd, str, &next); } static int print_srch_block(int fd, struct scoutfs_block_ref *ref, int level) { struct scoutfs_srch_parent *srp; struct scoutfs_srch_block *srb; struct scoutfs_srch_entry sre; struct scoutfs_srch_entry prev; u64 blkno; int pos; int ret; int err; int i; blkno = le64_to_cpu(ref->blkno); if (blkno == 0) return 0; ret = read_block(fd, blkno, SCOUTFS_BLOCK_LG_SHIFT, (void **)&srp); if (ret) goto out; srb = (void *)srp; printf("srch %sblock blkno %llu\n", level ? "parent " : "", blkno); print_block_header(&srp->hdr, SCOUTFS_BLOCK_LG_SIZE); for (i = 0; level > 0 && i < SCOUTFS_SRCH_PARENT_REFS; i++) { if (le64_to_cpu(srp->refs[i].blkno) == 0) continue; printf(" [%u]: blkno %llu seq %llu\n", i, le64_to_cpu(srp->refs[i].blkno), le64_to_cpu(srp->refs[i].seq)); } ret = 0; for (i = 0; level > 0 && i < SCOUTFS_SRCH_PARENT_REFS; i++) { if (le64_to_cpu(srp->refs[i].blkno) == 0) continue; err = print_srch_block(fd, &srp->refs[i], level - 1); if (err < 0 && ret == 0) ret = err; } if (level > 0) goto out; printf(" first "SRE_FMT" last "SRE_FMT" tail "SRE_FMT"\n" " entry_nr %u entry_bytes %u\n", SRE_A(&srb->first), SRE_A(&srb->last), SRE_A(&srb->tail), le32_to_cpu(srb->entry_nr), le32_to_cpu(srb->entry_bytes)); memset(&prev, 0, sizeof(prev)); pos = 0; for (i = 0; level == 0 && i < le32_to_cpu(srb->entry_nr); i++) { if (pos > SCOUTFS_SRCH_BLOCK_SAFE_BYTES) { ret = EIO; break; } ret = srch_decode_entry(srb->entries + pos, &sre, &prev); if (ret < 0) break; pos += ret; prev = sre; printf(" [%u]: (%u) "SRE_FMT"\n", i, ret, SRE_A(&sre)); } out: free(srp); return ret; } struct print_recursion_args { struct scoutfs_super_block *super; int fd; }; /* same as fs item but with a small header in the value */ static int print_log_trees_roots(struct scoutfs_key *key, void *val, unsigned val_len, void *arg) { struct scoutfs_log_trees *lt = val; struct print_recursion_args *pa = arg; int ret = 0; int err; /* XXX doesn't print the bloom block */ err = print_alloc_list_block(pa->fd, "lt_meta_avail", <->meta_avail.ref); if (err && !ret) ret = err; err = print_alloc_list_block(pa->fd, "lt_meta_freed", <->meta_freed.ref); if (err && !ret) ret = err; err = print_btree(pa->fd, pa->super, "data_avail", <->data_avail.root, print_alloc_item, NULL); if (err && !ret) ret = err; err = print_btree(pa->fd, pa->super, "data_freed", <->data_freed.root, print_alloc_item, NULL); if (err && !ret) ret = err; err = print_srch_block(pa->fd, <->srch_file.ref, lt->srch_file.height - 1); if (err && !ret) ret = err; err = print_btree(pa->fd, pa->super, "", <->item_root, print_logs_item, NULL); if (err && !ret) ret = err; return ret; } static int print_srch_root_files(struct scoutfs_key *key, void *val, unsigned val_len, void *arg) { struct print_recursion_args *pa = arg; struct scoutfs_srch_compact *sc; struct scoutfs_srch_file *sfl; int ret = 0; int i; if (key->sk_type == SCOUTFS_SRCH_PENDING_TYPE || key->sk_type == SCOUTFS_SRCH_BUSY_TYPE) { sc = val; for (i = 0; i < sc->nr; i++) { sfl = &sc->in[i].sfl; ret = print_srch_block(pa->fd, &sfl->ref, sfl->height - 1); if (ret < 0) break; } } else { sfl = val; ret = print_srch_block(pa->fd, &sfl->ref, sfl->height - 1); } return ret; } static int print_btree_leaf_items(int fd, struct scoutfs_super_block *super, struct scoutfs_block_ref *ref, print_item_func func, void *arg) { struct scoutfs_btree_item *item; struct scoutfs_avl_node *node; struct scoutfs_btree_block *bt; unsigned val_len; void *key; void *val; int ret; if (ref->blkno == 0) return 0; ret = read_block(fd, le64_to_cpu(ref->blkno), SCOUTFS_BLOCK_LG_SHIFT, (void **)&bt); if (ret) return ret; node = avl_first(&bt->item_root); while (node) { item = container_of(node, struct scoutfs_btree_item, node); val_len = le16_to_cpu(item->val_len); key = &item->key; val = (void *)bt + le16_to_cpu(item->val_off); if (bt->level > 0) { ret = print_btree_leaf_items(fd, super, val, func, arg); if (ret) break; continue; } else { func(key, val, val_len, arg); } node = avl_next(&bt->item_root, node); } free(bt); return 0; } static char *alloc_addr_str(union scoutfs_inet_addr *ia) { struct in_addr addr; char *quad; char *str; int len; memset(&addr, 0, sizeof(addr)); addr.s_addr = htonl(le32_to_cpu(ia->v4.addr)); quad = inet_ntoa(addr); if (quad == NULL) return NULL; len = snprintf(NULL, 0, "%s:%u", quad, le16_to_cpu(ia->v4.port)); if (len < 1 || len > 22) return NULL; len++; /* null */ str = malloc(len); if (!str) return NULL; snprintf(str, len, "%s:%u", quad, le16_to_cpu(ia->v4.port)); return str; } #define OFF_NAME(x) \ { offsetof(struct scoutfs_quorum_block, x), __stringify_1(x) } static int print_quorum_blocks(int fd, struct scoutfs_super_block *super) { struct print_events { size_t offset; char *name; } events[] = { OFF_NAME(write), OFF_NAME(update_term), OFF_NAME(set_leader), OFF_NAME(clear_leader), OFF_NAME(fenced), }; struct scoutfs_quorum_block *blk = NULL; struct scoutfs_quorum_block_event *ev; char *log_addr = NULL; u64 blkno; int ret; int i; int e; for (i = 0; i < SCOUTFS_QUORUM_BLOCKS; i++) { blkno = SCOUTFS_QUORUM_BLKNO + i; free(blk); ret = read_block(fd, blkno, SCOUTFS_BLOCK_SM_SHIFT, (void **)&blk); if (ret) goto out; printf("quorum blkno %llu (slot %llu)\n", blkno, blkno - SCOUTFS_QUORUM_BLKNO); print_block_header(&blk->hdr, SCOUTFS_BLOCK_SM_SIZE); printf(" term %llu random_write_mark 0x%llx flags 0x%llx\n", le64_to_cpu(blk->term), le64_to_cpu(blk->random_write_mark), le64_to_cpu(blk->flags)); for (e = 0; e < array_size(events); e++) { ev = (void *)blk + events[e].offset; printf(" %12s: rid %016llx ts %llu.%08u\n", events[e].name, le64_to_cpu(ev->rid), le64_to_cpu(ev->ts.sec), le32_to_cpu(ev->ts.nsec)); } } ret = 0; out: free(log_addr); return ret; } static void print_super_block(struct scoutfs_super_block *super, u64 blkno) { char uuid_str[37]; char *addr; int i; uuid_unparse(super->uuid, uuid_str); if (!(le64_to_cpu(super->flags) && SCOUTFS_FLAG_IS_META_BDEV)) fprintf(stderr, "**** Printing metadata from a data device! Did you mean to do this? ****\n"); printf("super blkno %llu\n", blkno); print_block_header(&super->hdr, SCOUTFS_BLOCK_SM_SIZE); printf(" version %llx uuid %s\n", le64_to_cpu(super->version), uuid_str); printf(" flags: 0x%016llx\n", le64_to_cpu(super->flags)); /* XXX these are all in a crazy order */ printf(" next_ino %llu next_trans_seq %llu\n" " total_meta_blocks %llu first_meta_blkno %llu last_meta_blkno %llu\n" " total_data_blocks %llu first_data_blkno %llu last_data_blkno %llu\n" " meta_alloc[0]: "ALCROOT_F"\n" " meta_alloc[1]: "ALCROOT_F"\n" " data_alloc: "ALCROOT_F"\n" " server_meta_avail[0]: "AL_HEAD_F"\n" " server_meta_avail[1]: "AL_HEAD_F"\n" " server_meta_freed[0]: "AL_HEAD_F"\n" " server_meta_freed[1]: "AL_HEAD_F"\n" " mounted_clients root: height %u blkno %llu seq %llu\n" " srch_root root: height %u blkno %llu seq %llu\n" " trans_seqs root: height %u blkno %llu seq %llu\n" " fs_root btree root: height %u blkno %llu seq %llu\n", le64_to_cpu(super->next_ino), le64_to_cpu(super->next_trans_seq), le64_to_cpu(super->total_meta_blocks), le64_to_cpu(super->first_meta_blkno), le64_to_cpu(super->last_meta_blkno), le64_to_cpu(super->total_data_blocks), le64_to_cpu(super->first_data_blkno), le64_to_cpu(super->last_data_blkno), ALCROOT_A(&super->meta_alloc[0]), ALCROOT_A(&super->meta_alloc[1]), ALCROOT_A(&super->data_alloc), AL_HEAD_A(&super->server_meta_avail[0]), AL_HEAD_A(&super->server_meta_avail[1]), AL_HEAD_A(&super->server_meta_freed[0]), AL_HEAD_A(&super->server_meta_freed[1]), super->mounted_clients.height, le64_to_cpu(super->mounted_clients.ref.blkno), le64_to_cpu(super->mounted_clients.ref.seq), super->srch_root.height, le64_to_cpu(super->srch_root.ref.blkno), le64_to_cpu(super->srch_root.ref.seq), super->trans_seqs.height, le64_to_cpu(super->trans_seqs.ref.blkno), le64_to_cpu(super->trans_seqs.ref.seq), super->fs_root.height, le64_to_cpu(super->fs_root.ref.blkno), le64_to_cpu(super->fs_root.ref.seq)); printf(" quorum config version %llu\n", le64_to_cpu(super->qconf.version)); for (i = 0; i < array_size(super->qconf.slots); i++) { if (super->qconf.slots[i].addr.v4.family != cpu_to_le16(SCOUTFS_AF_IPV4)) continue; addr = alloc_addr_str(&super->qconf.slots[i].addr); if (addr) { printf(" quorum slot %2u: %s\n", i, addr); free(addr); } } } struct print_args { char *meta_device; }; static int print_volume(int fd) { struct scoutfs_super_block *super = NULL; struct print_recursion_args pa; char str[80]; int ret = 0; int err; int i; ret = read_block(fd, SCOUTFS_SUPER_BLKNO, SCOUTFS_BLOCK_SM_SHIFT, (void **)&super); if (ret) return ret; print_super_block(super, SCOUTFS_SUPER_BLKNO); ret = print_quorum_blocks(fd, super); err = print_btree(fd, super, "mounted_clients", &super->mounted_clients, print_mounted_client_entry, NULL); if (err && !ret) ret = err; err = print_btree(fd, super, "trans_seqs", &super->trans_seqs, print_trans_seqs_entry, NULL); if (err && !ret) ret = err; for (i = 0; i < array_size(super->server_meta_avail); i++) { snprintf(str, sizeof(str), "server_meta_avail[%u]", i); err = print_alloc_list_block(fd, str, &super->server_meta_avail[i].ref); if (err && !ret) ret = err; } for (i = 0; i < array_size(super->server_meta_freed); i++) { snprintf(str, sizeof(str), "server_meta_freed[%u]", i); err = print_alloc_list_block(fd, str, &super->server_meta_freed[i].ref); if (err && !ret) ret = err; } for (i = 0; i < array_size(super->meta_alloc); i++) { snprintf(str, sizeof(str), "meta_alloc[%u]", i); err = print_btree(fd, super, str, &super->meta_alloc[i].root, print_alloc_item, NULL); if (err && !ret) ret = err; } err = print_btree(fd, super, "data_alloc", &super->data_alloc.root, print_alloc_item, NULL); if (err && !ret) ret = err; err = print_btree(fd, super, "srch_root", &super->srch_root, print_srch_root_item, NULL); if (err && !ret) ret = err; err = print_btree(fd, super, "logs_root", &super->logs_root, print_log_trees_item, NULL); if (err && !ret) ret = err; pa.super = super; pa.fd = fd; err = print_btree_leaf_items(fd, super, &super->srch_root.ref, print_srch_root_files, &pa); if (err && !ret) ret = err; err = print_btree_leaf_items(fd, super, &super->logs_root.ref, print_log_trees_roots, &pa); if (err && !ret) ret = err; err = print_btree(fd, super, "fs_root", &super->fs_root, print_fs_item, NULL); if (err && !ret) ret = err; free(super); return ret; } static int do_print(struct print_args *args) { int ret; int fd; fd = open(args->meta_device, O_RDONLY); if (fd < 0) { ret = -errno; fprintf(stderr, "failed to open '%s': %s (%d)\n", args->meta_device, strerror(errno), errno); return ret; } ret = print_volume(fd); close(fd); return ret; }; static int parse_opt(int key, char *arg, struct argp_state *state) { struct print_args *args = state->input; switch (key) { case ARGP_KEY_ARG: if (!args->meta_device) args->meta_device = strdup_or_error(state, arg); else argp_error(state, "more than one argument given"); break; case ARGP_KEY_FINI: if (!args->meta_device) argp_error(state, "no metadata device argument given"); break; default: break; } return 0; } static struct argp argp = { NULL, parse_opt, "META-DEV", "Print metadata structures" }; static int print_cmd(int argc, char **argv) { struct print_args print_args = {NULL}; int ret; ret = argp_parse(&argp, argc, argv, 0, NULL, &print_args); if (ret) return ret; return do_print(&print_args); } static void __attribute__((constructor)) print_ctor(void) { cmd_register_argp("print", &argp, GROUP_DEBUG, print_cmd); }