From d38ab0922d0b4422e23a8c5fadeefeaf27f2b608 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Thu, 17 Jan 2008 04:59:50 +0000 Subject: [PATCH] HAMMER utilities: * Add a 'show' command to the hammer utility. This command dumps the B-Tree for a HAMMER filesystem, allowing me to see just how bad my spike code currently is. * Remove the ClusterSize global (well, move it to newfs_hammer), the hammer utilities pull the cluster size out of the volume header. * UsingSuperClusters is only used by newfs_hammer. Super-cluster use can be controlled on a volume-by-volume basis so pull the information out of the volume header. --- sbin/hammer/Makefile | 5 +- sbin/hammer/cmd_show.c | 155 +++++++++++++++++++++++++++++++ sbin/hammer/hammer.8 | 14 ++- sbin/hammer/hammer.c | 50 ++++++++-- sbin/hammer/hammer.h | 6 +- sbin/hammer/hammer_util.h | 6 +- sbin/hammer/{hammer.h => misc.c} | 24 +---- sbin/hammer/ondisk.c | 46 +++++++-- sbin/newfs_hammer/newfs_hammer.c | 5 +- 9 files changed, 270 insertions(+), 41 deletions(-) create mode 100644 sbin/hammer/cmd_show.c copy sbin/hammer/{hammer.h => misc.c} (76%) diff --git a/sbin/hammer/Makefile b/sbin/hammer/Makefile index 3b7d672e14..02c6e4f5d7 100644 --- a/sbin/hammer/Makefile +++ b/sbin/hammer/Makefile @@ -1,8 +1,9 @@ # -# $DragonFly: src/sbin/hammer/Makefile,v 1.2 2008/01/03 06:48:45 dillon Exp $ +# $DragonFly: src/sbin/hammer/Makefile,v 1.3 2008/01/17 04:59:48 dillon Exp $ PROG= hammer -SRCS= hammer.c buffer_alist.c ondisk.c cache.c super_alist.c +SRCS= hammer.c buffer_alist.c ondisk.c cache.c super_alist.c \ + misc.c cmd_show.c MAN= hammer.8 CFLAGS+= -I${.CURDIR}/../../sys -DALIST_NO_DEBUG diff --git a/sbin/hammer/cmd_show.c b/sbin/hammer/cmd_show.c new file mode 100644 index 0000000000..24fa8a2a86 --- /dev/null +++ b/sbin/hammer/cmd_show.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2008 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly: src/sbin/hammer/cmd_show.c,v 1.1 2008/01/17 04:59:48 dillon Exp $ + */ + +#include "hammer.h" + +static void print_btree_node(struct cluster_info *cluster, + int32_t node_offset, int depth); +static void print_btree_elm(hammer_btree_elm_t elm, int i, + u_int8_t type, const char *label); + +void +hammer_cmd_show(int32_t vol_no, int32_t clu_no, int depth) +{ + struct volume_info *volume; + struct cluster_info *cluster; + int32_t node_offset; + + if (vol_no == -1) { + if (RootVolNo < 0) + errx(1, "hammer show: root volume number unknown"); + vol_no = RootVolNo; + } + volume = get_volume(vol_no); + if (volume == NULL) + errx(1, "hammer show: Unable to locate volume %d", vol_no); + if (clu_no == -1) + clu_no = volume->ondisk->vol0_root_clu_no; + cluster = get_cluster(volume, clu_no, 0); + printf("show %d:%d root@%08x parent@%d:%d depth %d\n", + vol_no, clu_no, + cluster->ondisk->clu_btree_root, + cluster->ondisk->clu_btree_parent_vol_no, + cluster->ondisk->clu_btree_parent_clu_no, + depth); + node_offset = cluster->ondisk->clu_btree_root; + print_btree_node(cluster, node_offset, depth); +} + +static void +print_btree_node(struct cluster_info *cluster, int32_t node_offset, int depth) +{ + struct buffer_info *buffer = NULL; + hammer_node_ondisk_t node; + hammer_btree_elm_t elm; + int i; + + node = get_node(cluster, node_offset, &buffer); + + printf(" NODE %08x count=%d parent=%d type=%c depth=%d {\n", + node_offset, node->count, node->parent, + (node->type ? node->type : '?'), + depth); + + for (i = 0; i < node->count; ++i) + print_btree_elm(&node->elms[i], i, node->type, "ELM"); + if (node->type == HAMMER_BTREE_TYPE_INTERNAL) + print_btree_elm(&node->elms[i], i, node->type, "RBN"); + printf(" }\n"); + + for (i = 0; i < node->count; ++i) { + elm = &node->elms[i]; + + switch(node->type) { + case HAMMER_BTREE_TYPE_INTERNAL: + if (elm->internal.subtree_offset) { + print_btree_node(cluster, + elm->internal.subtree_offset, + depth + 1); + } + break; + case HAMMER_BTREE_TYPE_LEAF: + if (RecurseOpt && elm->leaf.base.btype == + HAMMER_BTREE_TYPE_SPIKE_END) { + hammer_cmd_show(elm->leaf.spike_vol_no, + elm->leaf.spike_clu_no, + depth + 1); + } + break; + } + } + rel_buffer(buffer); +} + +static +void +print_btree_elm(hammer_btree_elm_t elm, int i, + u_int8_t type, const char *label) +{ + printf("\t%s %2d %c ", + label, i, + (elm->base.btype ? elm->base.btype : '?')); + printf("obj=%016llx key=%016llx rt=%02x ot=%02x\n", + elm->base.obj_id, + elm->base.key, + elm->base.rec_type, + elm->base.obj_type); + printf("\t tids %016llx:%016llx ", + elm->base.create_tid, + elm->base.delete_tid); + + switch(type) { + case HAMMER_BTREE_TYPE_INTERNAL: + printf("suboff=%08x", elm->internal.subtree_offset); + break; + case HAMMER_BTREE_TYPE_LEAF: + switch(elm->base.btype) { + case HAMMER_BTREE_TYPE_RECORD: + break; + case HAMMER_BTREE_TYPE_SPIKE_BEG: + case HAMMER_BTREE_TYPE_SPIKE_END: + printf("spike %d:%d", + elm->leaf.spike_vol_no, + elm->leaf.spike_clu_no); + break; + } + break; + default: + break; + } + printf("\n"); +} + diff --git a/sbin/hammer/hammer.8 b/sbin/hammer/hammer.8 index 09b910439c..6540ca06cb 100644 --- a/sbin/hammer/hammer.8 +++ b/sbin/hammer/hammer.8 @@ -30,7 +30,7 @@ .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $DragonFly: src/sbin/hammer/hammer.8,v 1.1 2008/01/01 00:57:57 dillon Exp $ +.\" $DragonFly: src/sbin/hammer/hammer.8,v 1.2 2008/01/17 04:59:48 dillon Exp $ .Dd December 31, 2007 .Dt HAMMER 8 .Os @@ -39,6 +39,8 @@ .Nd HAMMER file system utility .Sh SYNOPSIS .Nm +.Op Fl hr +.Op Fl f Ar blkdev[:blkdev]* .Ar command .Ar ... .Sh DESCRIPTION @@ -51,6 +53,10 @@ The options are as follows: .Bl -tag -width indent .It Fl h Get help +.It Fl r +Specify recursion for those commands which support it. +.It Fl f Ar blkdev[:blkdev]* +Specify the volumes making up a HAMMER filesystem. .El .Pp The commands are as follows: @@ -66,6 +72,12 @@ specifies an exact as-of timestamp in local (not UTC) time. Set the TZ environment variable prior to running .Nm if you wish to specify the time by some other means. +.It Ar show Op vol_no[:clu_no] +Dump the B-Tree starting at the specified volume and cluster, or +at the root volume if not specified. +The B-Tree is dumped recursively if the +.Fl r +option is specified. .El .Sh EXAMPLES .Sh DIAGNOSTICS diff --git a/sbin/hammer/hammer.c b/sbin/hammer/hammer.c index 8ab38612b2..d1da77524c 100644 --- a/sbin/hammer/hammer.c +++ b/sbin/hammer/hammer.c @@ -31,26 +31,36 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sbin/hammer/hammer.c,v 1.2 2008/01/03 06:48:45 dillon Exp $ + * $DragonFly: src/sbin/hammer/hammer.c,v 1.3 2008/01/17 04:59:48 dillon Exp $ */ #include "hammer.h" static void hammer_parsetime(u_int64_t *tidp, const char *timestr); +static void hammer_parsedevs(const char *blkdevs); static void usage(int exit_code); +int RecurseOpt; + int main(int ac, char **av) { u_int64_t tid; int ch; int status; + char *blkdevs = NULL; - while ((ch = getopt(ac, av, "h")) != -1) { + while ((ch = getopt(ac, av, "hf:r")) != -1) { switch(ch) { case 'h': usage(0); /* not reached */ + case 'r': + RecurseOpt = 1; + break; + case 'f': + blkdevs = optarg; + break; default: usage(1); /* not reached */ @@ -81,12 +91,18 @@ main(int ac, char **av) errx(1, "uuids file does not have the DragonFly " "HAMMER filesystem type"); } - init_alist_templates(); - /* - * Additional commands - */ + init_alist_templates(); + if (strcmp(av[0], "show") == 0) { + int32_t vol_no = -1; + int32_t clu_no = -1; + hammer_parsedevs(blkdevs); + if (ac > 1) + sscanf(av[1], "%d:%d", &vol_no, &clu_no); + hammer_cmd_show(vol_no, clu_no, 0); + exit(0); + } usage(1); /* not reached */ return(0); @@ -157,6 +173,26 @@ hammer_parsetime(u_int64_t *tidp, const char *timestr) (seconds - (int)seconds) * 1000000000; } +static +void +hammer_parsedevs(const char *blkdevs) +{ + char *copy; + char *volname; + + if (blkdevs == NULL) { + errx(1, "A -f blkdevs specification is required " + "for this command"); + } + + copy = strdup(blkdevs); + while ((volname = copy) != NULL) { + if ((copy = strchr(copy, ':')) != NULL) + *copy++ = 0; + setup_volume(-1, volname, 0, O_RDONLY); + } +} + static void usage(int exit_code) @@ -165,8 +201,10 @@ usage(int exit_code) "hammer -h\n" "hammer now\n" "hammer stamp