xref: /dflybsd-src/sbin/hammer/cmd_blockmap.c (revision d50f9ae3448247db98eb135b85b2a32e6e4187f4)
1eb3f8f1fSMatthew Dillon /*
2eb3f8f1fSMatthew Dillon  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3eb3f8f1fSMatthew Dillon  *
4eb3f8f1fSMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
5eb3f8f1fSMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
6eb3f8f1fSMatthew Dillon  *
7eb3f8f1fSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
8eb3f8f1fSMatthew Dillon  * modification, are permitted provided that the following conditions
9eb3f8f1fSMatthew Dillon  * are met:
10eb3f8f1fSMatthew Dillon  *
11eb3f8f1fSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
12eb3f8f1fSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
13eb3f8f1fSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
14eb3f8f1fSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
15eb3f8f1fSMatthew Dillon  *    the documentation and/or other materials provided with the
16eb3f8f1fSMatthew Dillon  *    distribution.
17eb3f8f1fSMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
18eb3f8f1fSMatthew Dillon  *    contributors may be used to endorse or promote products derived
19eb3f8f1fSMatthew Dillon  *    from this software without specific, prior written permission.
20eb3f8f1fSMatthew Dillon  *
21eb3f8f1fSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22eb3f8f1fSMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23eb3f8f1fSMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24eb3f8f1fSMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25eb3f8f1fSMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26eb3f8f1fSMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27eb3f8f1fSMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28eb3f8f1fSMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29eb3f8f1fSMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30eb3f8f1fSMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31eb3f8f1fSMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32eb3f8f1fSMatthew Dillon  * SUCH DAMAGE.
33eb3f8f1fSMatthew Dillon  */
34eb3f8f1fSMatthew Dillon 
35eb3f8f1fSMatthew Dillon #include "hammer.h"
36eb3f8f1fSMatthew Dillon 
3741ae0862STomohiro Kusumi #include <sys/tree.h>
3841ae0862STomohiro Kusumi 
3995c0f6b0STomohiro Kusumi /*
4095c0f6b0STomohiro Kusumi  * Each collect covers 1<<(19+23) bytes address space of layer 1.
4195c0f6b0STomohiro Kusumi  * (plus a copy of 1<<23 bytes that holds layer2 entries in layer 1).
4295c0f6b0STomohiro Kusumi  */
436ed4c886SMatthew Dillon typedef struct collect {
440083f684STomohiro Kusumi 	RB_ENTRY(collect) entry;
4595c0f6b0STomohiro Kusumi 	hammer_off_t	phys_offset;  /* layer2 address pointed by layer1 */
465aa4f01cSTomohiro Kusumi 	hammer_off_t	*offsets;  /* big-block offset for layer2[i] */
4721e9e7d5STomohiro Kusumi 	hammer_blockmap_layer2_t track2;  /* track of layer2 entries */
4821e9e7d5STomohiro Kusumi 	hammer_blockmap_layer2_t layer2;  /* 1<<19 x 16 bytes entries */
4995c0f6b0STomohiro Kusumi 	int error;  /* # of inconsistencies */
506ed4c886SMatthew Dillon } *collect_t;
516ed4c886SMatthew Dillon 
520083f684STomohiro Kusumi static int
collect_compare(struct collect * c1,struct collect * c2)530083f684STomohiro Kusumi collect_compare(struct collect *c1, struct collect *c2)
540083f684STomohiro Kusumi {
550083f684STomohiro Kusumi 	if (c1->phys_offset < c2->phys_offset)
560083f684STomohiro Kusumi 		return(-1);
570083f684STomohiro Kusumi 	if (c1->phys_offset > c2->phys_offset)
580083f684STomohiro Kusumi 		return(1);
590083f684STomohiro Kusumi 	return(0);
600083f684STomohiro Kusumi }
610083f684STomohiro Kusumi 
62*d50f9ae3SSascha Wildner static RB_HEAD(collect_rb_tree, collect) CollectTree =
63*d50f9ae3SSascha Wildner 					RB_INITIALIZER(&CollectTree);
640083f684STomohiro Kusumi RB_PROTOTYPE2(collect_rb_tree, collect, entry, collect_compare, hammer_off_t);
650083f684STomohiro Kusumi RB_GENERATE2(collect_rb_tree, collect, entry, collect_compare, hammer_off_t,
660083f684STomohiro Kusumi 	phys_offset);
676ed4c886SMatthew Dillon 
68dce7ae2cSTomohiro Kusumi static void dump_blockmap(int zone);
69f8589256STomohiro Kusumi static void check_freemap(hammer_blockmap_t freemap);
706ed4c886SMatthew Dillon static void check_btree_node(hammer_off_t node_offset, int depth);
7153076cf0STomohiro Kusumi static void check_undo(hammer_blockmap_t undomap);
725f9a4634STomohiro Kusumi static __inline void collect_btree_root(hammer_off_t node_offset);
735f9a4634STomohiro Kusumi static __inline void collect_btree_internal(hammer_btree_elm_t elm);
745f9a4634STomohiro Kusumi static __inline void collect_btree_leaf(hammer_btree_elm_t elm);
75f8589256STomohiro Kusumi static __inline void collect_freemap_layer1(hammer_blockmap_t freemap);
7621e9e7d5STomohiro Kusumi static __inline void collect_freemap_layer2(hammer_blockmap_layer1_t layer1);
775f9a4634STomohiro Kusumi static __inline void collect_undo(hammer_off_t scan_offset,
785f9a4634STomohiro Kusumi 	hammer_fifo_head_t head);
79901e04c7STomohiro Kusumi static void collect_blockmap(hammer_off_t offset, int32_t length, int zone);
8021e9e7d5STomohiro Kusumi static hammer_blockmap_layer2_t collect_get_track(
81901e04c7STomohiro Kusumi 	collect_t collect, hammer_off_t offset, int zone,
8221e9e7d5STomohiro Kusumi 	hammer_blockmap_layer2_t layer2);
836ed4c886SMatthew Dillon static collect_t collect_get(hammer_off_t phys_offset);
846ed4c886SMatthew Dillon static void dump_collect_table(void);
8564321bafSTomohiro Kusumi static void dump_collect(collect_t collect, zone_stat_t stats);
86eb3f8f1fSMatthew Dillon 
874a08dcf4STomohiro Kusumi static int num_bad_layer1 = 0;
884a08dcf4STomohiro Kusumi static int num_bad_layer2 = 0;
894a08dcf4STomohiro Kusumi static int num_bad_node = 0;
904a08dcf4STomohiro Kusumi 
91eb3f8f1fSMatthew Dillon void
hammer_cmd_blockmap(void)92eb3f8f1fSMatthew Dillon hammer_cmd_blockmap(void)
93eb3f8f1fSMatthew Dillon {
94dce7ae2cSTomohiro Kusumi 	dump_blockmap(HAMMER_ZONE_FREEMAP_INDEX);
95eb3f8f1fSMatthew Dillon }
96eb3f8f1fSMatthew Dillon 
97eb3f8f1fSMatthew Dillon static
98eb3f8f1fSMatthew Dillon void
dump_blockmap(int zone)99dce7ae2cSTomohiro Kusumi dump_blockmap(int zone)
100eb3f8f1fSMatthew Dillon {
1012dba5fa7STomohiro Kusumi 	volume_info_t root_volume;
102eb3f8f1fSMatthew Dillon 	hammer_blockmap_t rootmap;
10321e9e7d5STomohiro Kusumi 	hammer_blockmap_layer1_t layer1;
10421e9e7d5STomohiro Kusumi 	hammer_blockmap_layer2_t layer2;
105c17fa600STomohiro Kusumi 	buffer_info_t buffer1 = NULL;
106c17fa600STomohiro Kusumi 	buffer_info_t buffer2 = NULL;
107eb3f8f1fSMatthew Dillon 	hammer_off_t layer1_offset;
108eb3f8f1fSMatthew Dillon 	hammer_off_t layer2_offset;
109625b4957STomohiro Kusumi 	hammer_off_t phys_offset;
110625b4957STomohiro Kusumi 	hammer_off_t block_offset;
11164321bafSTomohiro Kusumi 	zone_stat_t stats = NULL;
1121f4a137dSTomohiro Kusumi 	int xerr, aerr, ferr;
113eb3f8f1fSMatthew Dillon 
11442700c9dSTomohiro Kusumi 	root_volume = get_root_volume();
115eb3f8f1fSMatthew Dillon 	rootmap = &root_volume->ondisk->vol0_blockmap[zone];
116eb3f8f1fSMatthew Dillon 	assert(rootmap->phys_offset != 0);
117eb3f8f1fSMatthew Dillon 
118dce7ae2cSTomohiro Kusumi 	print_blockmap(root_volume);
119eb3f8f1fSMatthew Dillon 
120284b6ac2STomohiro Kusumi 	if (VerboseOpt)
121284b6ac2STomohiro Kusumi 		stats = hammer_init_zone_stat();
122284b6ac2STomohiro Kusumi 
123625b4957STomohiro Kusumi 	for (phys_offset = HAMMER_ZONE_ENCODE(zone, 0);
124625b4957STomohiro Kusumi 	     phys_offset < HAMMER_ZONE_ENCODE(zone, HAMMER_OFF_LONG_MASK);
125625b4957STomohiro Kusumi 	     phys_offset += HAMMER_BLOCKMAP_LAYER2) {
126eb3f8f1fSMatthew Dillon 		/*
127eb3f8f1fSMatthew Dillon 		 * Dive layer 1.
128eb3f8f1fSMatthew Dillon 		 */
129eb3f8f1fSMatthew Dillon 		layer1_offset = rootmap->phys_offset +
130625b4957STomohiro Kusumi 				HAMMER_BLOCKMAP_LAYER1_OFFSET(phys_offset);
131eb3f8f1fSMatthew Dillon 		layer1 = get_buffer_data(layer1_offset, &buffer1, 0);
1324a08dcf4STomohiro Kusumi 
1334a08dcf4STomohiro Kusumi 		xerr = ' ';  /* good */
1344c09d9c4SMatthew Dillon 		if (!hammer_crc_test_layer1(HammerVersion, layer1)) {
135822e0d97SMatthew Dillon 			xerr = 'B';
1364a08dcf4STomohiro Kusumi 			++num_bad_layer1;
1374a08dcf4STomohiro Kusumi 		}
138822e0d97SMatthew Dillon 		if (xerr == ' ' &&
139f254e677STomohiro Kusumi 		    layer1->phys_offset == HAMMER_BLOCKMAP_UNAVAIL) {
140da44aa75SMatthew Dillon 			continue;
141f254e677STomohiro Kusumi 		}
142a276dc6bSMatthew Dillon 		printf("%c layer1 %016jx @%016jx blocks-free %jd\n",
143a276dc6bSMatthew Dillon 			xerr,
144625b4957STomohiro Kusumi 			(uintmax_t)phys_offset,
145a276dc6bSMatthew Dillon 			(uintmax_t)layer1->phys_offset,
146a276dc6bSMatthew Dillon 			(intmax_t)layer1->blocks_free);
1470c37fec9STomohiro Kusumi 
148625b4957STomohiro Kusumi 		for (block_offset = 0;
149625b4957STomohiro Kusumi 		     block_offset < HAMMER_BLOCKMAP_LAYER2;
150625b4957STomohiro Kusumi 		     block_offset += HAMMER_BIGBLOCK_SIZE) {
151625b4957STomohiro Kusumi 			hammer_off_t zone_offset = phys_offset + block_offset;
152eb3f8f1fSMatthew Dillon 			/*
153e04ee2deSTomohiro Kusumi 			 * Dive layer 2, each entry represents a big-block.
154eb3f8f1fSMatthew Dillon 			 */
155eb3f8f1fSMatthew Dillon 			layer2_offset = layer1->phys_offset +
156625b4957STomohiro Kusumi 					HAMMER_BLOCKMAP_LAYER2_OFFSET(block_offset);
157eb3f8f1fSMatthew Dillon 			layer2 = get_buffer_data(layer2_offset, &buffer2, 0);
1584a08dcf4STomohiro Kusumi 
1591f4a137dSTomohiro Kusumi 			xerr = aerr = ferr = ' ';  /* good */
1604c09d9c4SMatthew Dillon 			if (!hammer_crc_test_layer2(HammerVersion, layer2)) {
161822e0d97SMatthew Dillon 				xerr = 'B';
1624a08dcf4STomohiro Kusumi 				++num_bad_layer2;
1634a08dcf4STomohiro Kusumi 			}
1641f4a137dSTomohiro Kusumi 			if (layer2->append_off > HAMMER_BIGBLOCK_SIZE) {
1651f4a137dSTomohiro Kusumi 				aerr = 'A';
1661f4a137dSTomohiro Kusumi 				++num_bad_layer2;
1671f4a137dSTomohiro Kusumi 			}
1681f4a137dSTomohiro Kusumi 			if (layer2->bytes_free < 0 ||
1691f4a137dSTomohiro Kusumi 			    layer2->bytes_free > HAMMER_BIGBLOCK_SIZE) {
1701f4a137dSTomohiro Kusumi 				ferr = 'F';
1711f4a137dSTomohiro Kusumi 				++num_bad_layer2;
1721f4a137dSTomohiro Kusumi 			}
1731f4a137dSTomohiro Kusumi 
1741f4a137dSTomohiro Kusumi 			if (VerboseOpt < 2 &&
1751f4a137dSTomohiro Kusumi 			    xerr == ' ' && aerr == ' ' && ferr == ' ' &&
176f254e677STomohiro Kusumi 			    layer2->zone == HAMMER_ZONE_UNAVAIL_INDEX) {
177320e3007STomohiro Kusumi 				break;
178f254e677STomohiro Kusumi 			}
1791f4a137dSTomohiro Kusumi 			printf("%c%c%c     %016jx zone=%-2d ",
1801f4a137dSTomohiro Kusumi 				xerr, aerr, ferr, (uintmax_t)zone_offset, layer2->zone);
181f254e677STomohiro Kusumi 			if (VerboseOpt) {
182e7a33960STomohiro Kusumi 				printf("vol=%-3d L1#=%-6d L2#=%-6d L1=%-7lu L2=%-7lu ",
183625b4957STomohiro Kusumi 					HAMMER_VOL_DECODE(zone_offset),
184625b4957STomohiro Kusumi 					HAMMER_BLOCKMAP_LAYER1_INDEX(zone_offset),
185625b4957STomohiro Kusumi 					HAMMER_BLOCKMAP_LAYER2_INDEX(zone_offset),
186625b4957STomohiro Kusumi 					HAMMER_BLOCKMAP_LAYER1_OFFSET(zone_offset),
187625b4957STomohiro Kusumi 					HAMMER_BLOCKMAP_LAYER2_OFFSET(zone_offset));
188f254e677STomohiro Kusumi 			}
189504ef445STomohiro Kusumi 			printf("app=%-7d free=%-7d",
190da44aa75SMatthew Dillon 				layer2->append_off,
191eb3f8f1fSMatthew Dillon 				layer2->bytes_free);
1925d96e8deSTomohiro Kusumi 			if (VerboseOpt) {
19333614697STomohiro Kusumi 				double bytes_used = HAMMER_BIGBLOCK_SIZE -
1945d96e8deSTomohiro Kusumi 					layer2->bytes_free;
1955d96e8deSTomohiro Kusumi 				printf(" fill=%-5.1lf crc=%08x-%08x\n",
1965d96e8deSTomohiro Kusumi 					bytes_used * 100 / HAMMER_BIGBLOCK_SIZE,
197504ef445STomohiro Kusumi 					layer1->layer1_crc,
198504ef445STomohiro Kusumi 					layer2->entry_crc);
1995d96e8deSTomohiro Kusumi 			} else {
200504ef445STomohiro Kusumi 				printf("\n");
2015d96e8deSTomohiro Kusumi 			}
202284b6ac2STomohiro Kusumi 
203dd96867bSTomohiro Kusumi 			if (stats)
204284b6ac2STomohiro Kusumi 				hammer_add_zone_stat_layer2(stats, layer2);
205eb3f8f1fSMatthew Dillon 		}
206eb3f8f1fSMatthew Dillon 	}
207eb3f8f1fSMatthew Dillon 	rel_buffer(buffer1);
208eb3f8f1fSMatthew Dillon 	rel_buffer(buffer2);
209284b6ac2STomohiro Kusumi 
210dd96867bSTomohiro Kusumi 	if (stats) {
211284b6ac2STomohiro Kusumi 		hammer_print_zone_stat(stats);
212284b6ac2STomohiro Kusumi 		hammer_cleanup_zone_stat(stats);
213284b6ac2STomohiro Kusumi 	}
2144a08dcf4STomohiro Kusumi 
21552e2f1b5STomohiro Kusumi 	if (num_bad_layer1 || VerboseOpt)
2164a08dcf4STomohiro Kusumi 		printf("%d bad layer1\n", num_bad_layer1);
21752e2f1b5STomohiro Kusumi 	if (num_bad_layer2 || VerboseOpt)
2184a08dcf4STomohiro Kusumi 		printf("%d bad layer2\n", num_bad_layer1);
2194a08dcf4STomohiro Kusumi }
220eb3f8f1fSMatthew Dillon 
2216ed4c886SMatthew Dillon void
hammer_cmd_checkmap(void)2226ed4c886SMatthew Dillon hammer_cmd_checkmap(void)
2236ed4c886SMatthew Dillon {
2242dba5fa7STomohiro Kusumi 	volume_info_t volume;
225f8589256STomohiro Kusumi 	hammer_blockmap_t freemap;
22653076cf0STomohiro Kusumi 	hammer_blockmap_t undomap;
2276ed4c886SMatthew Dillon 	hammer_off_t node_offset;
2286ed4c886SMatthew Dillon 
22942700c9dSTomohiro Kusumi 	volume = get_root_volume();
2306ed4c886SMatthew Dillon 	node_offset = volume->ondisk->vol0_btree_root;
231f8589256STomohiro Kusumi 	freemap = &volume->ondisk->vol0_blockmap[HAMMER_ZONE_FREEMAP_INDEX];
23253076cf0STomohiro Kusumi 	undomap = &volume->ondisk->vol0_blockmap[HAMMER_ZONE_UNDO_INDEX];
233d2bf3c30STomohiro Kusumi 
234dce7ae2cSTomohiro Kusumi 	print_blockmap(volume);
2356ed4c886SMatthew Dillon 
236f8589256STomohiro Kusumi 	printf("Collecting allocation info from freemap: ");
237f8589256STomohiro Kusumi 	fflush(stdout);
238f8589256STomohiro Kusumi 	check_freemap(freemap);
239f8589256STomohiro Kusumi 	printf("done\n");
240f8589256STomohiro Kusumi 
2416ed4c886SMatthew Dillon 	printf("Collecting allocation info from B-Tree: ");
2426ed4c886SMatthew Dillon 	fflush(stdout);
2436ed4c886SMatthew Dillon 	check_btree_node(node_offset, 0);
2446ed4c886SMatthew Dillon 	printf("done\n");
2458fd2cc39STomohiro Kusumi 
246d2bf3c30STomohiro Kusumi 	printf("Collecting allocation info from UNDO: ");
247d2bf3c30STomohiro Kusumi 	fflush(stdout);
24853076cf0STomohiro Kusumi 	check_undo(undomap);
249d2bf3c30STomohiro Kusumi 	printf("done\n");
250d2bf3c30STomohiro Kusumi 
251d2bf3c30STomohiro Kusumi 	dump_collect_table();
2526ed4c886SMatthew Dillon }
2536ed4c886SMatthew Dillon 
254005a4da7STomohiro Kusumi static
255005a4da7STomohiro Kusumi void
check_freemap(hammer_blockmap_t freemap)256f8589256STomohiro Kusumi check_freemap(hammer_blockmap_t freemap)
257f8589256STomohiro Kusumi {
258f8589256STomohiro Kusumi 	hammer_off_t offset;
259c17fa600STomohiro Kusumi 	buffer_info_t buffer1 = NULL;
26021e9e7d5STomohiro Kusumi 	hammer_blockmap_layer1_t layer1;
261f8589256STomohiro Kusumi 	int i;
262f8589256STomohiro Kusumi 
263f8589256STomohiro Kusumi 	collect_freemap_layer1(freemap);
264f8589256STomohiro Kusumi 
26537fa1bc7STomohiro Kusumi 	for (i = 0; i < HAMMER_BLOCKMAP_RADIX1; ++i) {
266f8589256STomohiro Kusumi 		offset = freemap->phys_offset + i * sizeof(*layer1);
267f8589256STomohiro Kusumi 		layer1 = get_buffer_data(offset, &buffer1, 0);
268f8589256STomohiro Kusumi 		if (layer1->phys_offset != HAMMER_BLOCKMAP_UNAVAIL)
269f8589256STomohiro Kusumi 			collect_freemap_layer2(layer1);
270f8589256STomohiro Kusumi 	}
271f8589256STomohiro Kusumi 	rel_buffer(buffer1);
272f8589256STomohiro Kusumi }
273f8589256STomohiro Kusumi 
274005a4da7STomohiro Kusumi static
275005a4da7STomohiro Kusumi void
check_btree_node(hammer_off_t node_offset,int depth)2766ed4c886SMatthew Dillon check_btree_node(hammer_off_t node_offset, int depth)
2776ed4c886SMatthew Dillon {
278c17fa600STomohiro Kusumi 	buffer_info_t buffer = NULL;
2796ed4c886SMatthew Dillon 	hammer_node_ondisk_t node;
2806ed4c886SMatthew Dillon 	hammer_btree_elm_t elm;
2816ed4c886SMatthew Dillon 	int i;
2824a08dcf4STomohiro Kusumi 	char badc = ' ';  /* good */
2834a08dcf4STomohiro Kusumi 	char badm = ' ';  /* good */
2846ed4c886SMatthew Dillon 
28553076cf0STomohiro Kusumi 	if (depth == 0)
28653076cf0STomohiro Kusumi 		collect_btree_root(node_offset);
2871ba4249fSTomohiro Kusumi 	node = get_buffer_data(node_offset, &buffer, 0);
2886ed4c886SMatthew Dillon 
2894a08dcf4STomohiro Kusumi 	if (node == NULL) {
2906ed4c886SMatthew Dillon 		badc = 'B';
2914a08dcf4STomohiro Kusumi 		badm = 'I';
2924c09d9c4SMatthew Dillon 	} else if (!hammer_crc_test_btree(HammerVersion, node)) {
2934a08dcf4STomohiro Kusumi 		badc = 'B';
2944a08dcf4STomohiro Kusumi 	}
2956ed4c886SMatthew Dillon 
2964a08dcf4STomohiro Kusumi 	if (badm != ' ' || badc != ' ') {  /* not good */
2974a08dcf4STomohiro Kusumi 		++num_bad_node;
2984a08dcf4STomohiro Kusumi 		printf("%c%c   NODE %016jx ",
2994a08dcf4STomohiro Kusumi 			badc, badm, (uintmax_t)node_offset);
3004a08dcf4STomohiro Kusumi 		if (node == NULL) {
3014a08dcf4STomohiro Kusumi 			printf("(IO ERROR)\n");
30210de5026STomohiro Kusumi 			rel_buffer(buffer);
3034a08dcf4STomohiro Kusumi 			return;
3044a08dcf4STomohiro Kusumi 		} else {
3054a08dcf4STomohiro Kusumi 			printf("cnt=%02d p=%016jx type=%c depth=%d mirror=%016jx\n",
3064a08dcf4STomohiro Kusumi 			       node->count,
3076ed4c886SMatthew Dillon 			       (uintmax_t)node->parent,
3084a08dcf4STomohiro Kusumi 			       (node->type ? node->type : '?'),
3094a08dcf4STomohiro Kusumi 			       depth,
3104a08dcf4STomohiro Kusumi 			       (uintmax_t)node->mirror_tid);
3114a08dcf4STomohiro Kusumi 		}
3126ed4c886SMatthew Dillon 	}
3136ed4c886SMatthew Dillon 
3146ed4c886SMatthew Dillon 	for (i = 0; i < node->count; ++i) {
3156ed4c886SMatthew Dillon 		elm = &node->elms[i];
3166ed4c886SMatthew Dillon 
3176ed4c886SMatthew Dillon 		switch(node->type) {
3186ed4c886SMatthew Dillon 		case HAMMER_BTREE_TYPE_INTERNAL:
3196ed4c886SMatthew Dillon 			if (elm->internal.subtree_offset) {
3206cf258d9STomohiro Kusumi 				collect_btree_internal(elm);
3216ed4c886SMatthew Dillon 				check_btree_node(elm->internal.subtree_offset,
3226ed4c886SMatthew Dillon 						 depth + 1);
3236ed4c886SMatthew Dillon 			}
3246ed4c886SMatthew Dillon 			break;
3256ed4c886SMatthew Dillon 		case HAMMER_BTREE_TYPE_LEAF:
3266ed4c886SMatthew Dillon 			if (elm->leaf.data_offset)
3276cf258d9STomohiro Kusumi 				collect_btree_leaf(elm);
3286ed4c886SMatthew Dillon 			break;
3292222420cSTomohiro Kusumi 		default:
330e0c64b7dSTomohiro Kusumi 			assert(!DebugOpt);
3312222420cSTomohiro Kusumi 			break;
3326ed4c886SMatthew Dillon 		}
3336ed4c886SMatthew Dillon 	}
3346ed4c886SMatthew Dillon 	rel_buffer(buffer);
3356ed4c886SMatthew Dillon }
3366ed4c886SMatthew Dillon 
337005a4da7STomohiro Kusumi static
338005a4da7STomohiro Kusumi void
check_undo(hammer_blockmap_t undomap)33953076cf0STomohiro Kusumi check_undo(hammer_blockmap_t undomap)
340d2bf3c30STomohiro Kusumi {
341c17fa600STomohiro Kusumi 	buffer_info_t buffer = NULL;
342d2bf3c30STomohiro Kusumi 	hammer_off_t scan_offset;
343d2bf3c30STomohiro Kusumi 	hammer_fifo_head_t head;
344d2bf3c30STomohiro Kusumi 
345459a6a40STomohiro Kusumi 	scan_offset = HAMMER_ENCODE_UNDO(0);
34653076cf0STomohiro Kusumi 	while (scan_offset < undomap->alloc_offset) {
347d2bf3c30STomohiro Kusumi 		head = get_buffer_data(scan_offset, &buffer, 0);
348d2bf3c30STomohiro Kusumi 		switch (head->hdr_type) {
349d2bf3c30STomohiro Kusumi 		case HAMMER_HEAD_TYPE_PAD:
350d2bf3c30STomohiro Kusumi 		case HAMMER_HEAD_TYPE_DUMMY:
351d2bf3c30STomohiro Kusumi 		case HAMMER_HEAD_TYPE_UNDO:
352d2bf3c30STomohiro Kusumi 		case HAMMER_HEAD_TYPE_REDO:
353d2bf3c30STomohiro Kusumi 			collect_undo(scan_offset, head);
354d2bf3c30STomohiro Kusumi 			break;
3552222420cSTomohiro Kusumi 		default:
356e0c64b7dSTomohiro Kusumi 			assert(!DebugOpt);
3572222420cSTomohiro Kusumi 			break;
358d2bf3c30STomohiro Kusumi 		}
359d2bf3c30STomohiro Kusumi 		if ((head->hdr_size & HAMMER_HEAD_ALIGN_MASK) ||
360d2bf3c30STomohiro Kusumi 		     head->hdr_size == 0 ||
361d2bf3c30STomohiro Kusumi 		     head->hdr_size > HAMMER_UNDO_ALIGN -
362d2bf3c30STomohiro Kusumi 			((u_int)scan_offset & HAMMER_UNDO_MASK)) {
363d2bf3c30STomohiro Kusumi 			printf("Illegal size, skipping to next boundary\n");
36419836c70STomohiro Kusumi 			scan_offset = HAMMER_UNDO_DOALIGN(scan_offset);
365d2bf3c30STomohiro Kusumi 		} else {
366d2bf3c30STomohiro Kusumi 			scan_offset += head->hdr_size;
367d2bf3c30STomohiro Kusumi 		}
368d2bf3c30STomohiro Kusumi 	}
369d2bf3c30STomohiro Kusumi 	rel_buffer(buffer);
370d2bf3c30STomohiro Kusumi }
371d2bf3c30STomohiro Kusumi 
3725f9a4634STomohiro Kusumi static __inline
3736ed4c886SMatthew Dillon void
collect_freemap_layer1(hammer_blockmap_t freemap)374f8589256STomohiro Kusumi collect_freemap_layer1(hammer_blockmap_t freemap)
375f8589256STomohiro Kusumi {
376f8589256STomohiro Kusumi 	/*
377f8589256STomohiro Kusumi 	 * This translation is necessary to do checkmap properly
378f8589256STomohiro Kusumi 	 * as zone4 is really just zone2 address space.
379f8589256STomohiro Kusumi 	 */
380f8589256STomohiro Kusumi 	hammer_off_t zone4_offset = hammer_xlate_to_zoneX(
381f8589256STomohiro Kusumi 		HAMMER_ZONE_FREEMAP_INDEX, freemap->phys_offset);
382f8589256STomohiro Kusumi 	collect_blockmap(zone4_offset, HAMMER_BIGBLOCK_SIZE,
383f8589256STomohiro Kusumi 		HAMMER_ZONE_FREEMAP_INDEX);
384f8589256STomohiro Kusumi }
385f8589256STomohiro Kusumi 
386f8589256STomohiro Kusumi static __inline
387f8589256STomohiro Kusumi void
collect_freemap_layer2(hammer_blockmap_layer1_t layer1)38821e9e7d5STomohiro Kusumi collect_freemap_layer2(hammer_blockmap_layer1_t layer1)
389f8589256STomohiro Kusumi {
390f8589256STomohiro Kusumi 	/*
391f8589256STomohiro Kusumi 	 * This translation is necessary to do checkmap properly
392f8589256STomohiro Kusumi 	 * as zone4 is really just zone2 address space.
393f8589256STomohiro Kusumi 	 */
394f8589256STomohiro Kusumi 	hammer_off_t zone4_offset = hammer_xlate_to_zoneX(
395f8589256STomohiro Kusumi 		HAMMER_ZONE_FREEMAP_INDEX, layer1->phys_offset);
396f8589256STomohiro Kusumi 	collect_blockmap(zone4_offset, HAMMER_BIGBLOCK_SIZE,
397f8589256STomohiro Kusumi 		HAMMER_ZONE_FREEMAP_INDEX);
398f8589256STomohiro Kusumi }
399f8589256STomohiro Kusumi 
400f8589256STomohiro Kusumi static __inline
401f8589256STomohiro Kusumi void
collect_btree_root(hammer_off_t node_offset)4026cf258d9STomohiro Kusumi collect_btree_root(hammer_off_t node_offset)
4036cf258d9STomohiro Kusumi {
4046cf258d9STomohiro Kusumi 	collect_blockmap(node_offset,
405901e04c7STomohiro Kusumi 		sizeof(struct hammer_node_ondisk),  /* 4KB */
406901e04c7STomohiro Kusumi 		HAMMER_ZONE_BTREE_INDEX);
4076cf258d9STomohiro Kusumi }
4086cf258d9STomohiro Kusumi 
4095f9a4634STomohiro Kusumi static __inline
4106cf258d9STomohiro Kusumi void
collect_btree_internal(hammer_btree_elm_t elm)4116cf258d9STomohiro Kusumi collect_btree_internal(hammer_btree_elm_t elm)
4126cf258d9STomohiro Kusumi {
4136cf258d9STomohiro Kusumi 	collect_blockmap(elm->internal.subtree_offset,
414901e04c7STomohiro Kusumi 		sizeof(struct hammer_node_ondisk),  /* 4KB */
415901e04c7STomohiro Kusumi 		HAMMER_ZONE_BTREE_INDEX);
4166cf258d9STomohiro Kusumi }
4176cf258d9STomohiro Kusumi 
4185f9a4634STomohiro Kusumi static __inline
4196cf258d9STomohiro Kusumi void
collect_btree_leaf(hammer_btree_elm_t elm)4206cf258d9STomohiro Kusumi collect_btree_leaf(hammer_btree_elm_t elm)
4216cf258d9STomohiro Kusumi {
422901e04c7STomohiro Kusumi 	int zone;
423901e04c7STomohiro Kusumi 
424901e04c7STomohiro Kusumi 	switch (elm->base.rec_type) {
425901e04c7STomohiro Kusumi 	case HAMMER_RECTYPE_INODE:
426901e04c7STomohiro Kusumi 	case HAMMER_RECTYPE_DIRENTRY:
427901e04c7STomohiro Kusumi 	case HAMMER_RECTYPE_EXT:
428901e04c7STomohiro Kusumi 	case HAMMER_RECTYPE_FIX:
429901e04c7STomohiro Kusumi 	case HAMMER_RECTYPE_PFS:
430901e04c7STomohiro Kusumi 	case HAMMER_RECTYPE_SNAPSHOT:
431901e04c7STomohiro Kusumi 	case HAMMER_RECTYPE_CONFIG:
432901e04c7STomohiro Kusumi 		zone = HAMMER_ZONE_META_INDEX;
433901e04c7STomohiro Kusumi 		break;
434901e04c7STomohiro Kusumi 	case HAMMER_RECTYPE_DATA:
435901e04c7STomohiro Kusumi 	case HAMMER_RECTYPE_DB:
43622c06dfeSTomohiro Kusumi 		zone = hammer_data_zone_index(elm->leaf.data_len);
437901e04c7STomohiro Kusumi 		break;
438901e04c7STomohiro Kusumi 	default:
439901e04c7STomohiro Kusumi 		zone = HAMMER_ZONE_UNAVAIL_INDEX;
440901e04c7STomohiro Kusumi 		break;
441901e04c7STomohiro Kusumi 	}
4426cf258d9STomohiro Kusumi 	collect_blockmap(elm->leaf.data_offset,
443f097bffeSTomohiro Kusumi 		HAMMER_DATA_DOALIGN(elm->leaf.data_len), zone);
4446cf258d9STomohiro Kusumi }
4456cf258d9STomohiro Kusumi 
4465f9a4634STomohiro Kusumi static __inline
4476cf258d9STomohiro Kusumi void
collect_undo(hammer_off_t scan_offset,hammer_fifo_head_t head)448d2bf3c30STomohiro Kusumi collect_undo(hammer_off_t scan_offset, hammer_fifo_head_t head)
449d2bf3c30STomohiro Kusumi {
450901e04c7STomohiro Kusumi 	collect_blockmap(scan_offset, head->hdr_size,
451901e04c7STomohiro Kusumi 		HAMMER_ZONE_UNDO_INDEX);
452d2bf3c30STomohiro Kusumi }
453d2bf3c30STomohiro Kusumi 
454d2bf3c30STomohiro Kusumi static
455d2bf3c30STomohiro Kusumi void
collect_blockmap(hammer_off_t offset,int32_t length,int zone)456901e04c7STomohiro Kusumi collect_blockmap(hammer_off_t offset, int32_t length, int zone)
4576ed4c886SMatthew Dillon {
4586ed4c886SMatthew Dillon 	struct hammer_blockmap_layer1 layer1;
4596ed4c886SMatthew Dillon 	struct hammer_blockmap_layer2 layer2;
46021e9e7d5STomohiro Kusumi 	hammer_blockmap_layer2_t track2;
4616cf258d9STomohiro Kusumi 	hammer_off_t result_offset;
4626ed4c886SMatthew Dillon 	collect_t collect;
4636ed4c886SMatthew Dillon 	int error;
4646ed4c886SMatthew Dillon 
4658b916bc2STomohiro Kusumi 	result_offset = blockmap_lookup_save(offset, &layer1, &layer2, &error);
466e0c64b7dSTomohiro Kusumi 	if (DebugOpt) {
467901e04c7STomohiro Kusumi 		assert(HAMMER_ZONE_DECODE(offset) == zone);
4689b6e7743STomohiro Kusumi 		assert(hammer_is_zone_raw_buffer(result_offset));
4696cf258d9STomohiro Kusumi 		assert(error == 0);
4706cf258d9STomohiro Kusumi 	}
4716cf258d9STomohiro Kusumi 	collect = collect_get(layer1.phys_offset); /* layer2 address */
4725aa4f01cSTomohiro Kusumi 	track2 = collect_get_track(collect, result_offset, zone, &layer2);
4736cf258d9STomohiro Kusumi 	track2->bytes_free -= length;
4746ed4c886SMatthew Dillon }
4756ed4c886SMatthew Dillon 
4766ed4c886SMatthew Dillon static
4776ed4c886SMatthew Dillon collect_t
collect_get(hammer_off_t phys_offset)4786ed4c886SMatthew Dillon collect_get(hammer_off_t phys_offset)
4796ed4c886SMatthew Dillon {
4806ed4c886SMatthew Dillon 	collect_t collect;
4816ed4c886SMatthew Dillon 
4820083f684STomohiro Kusumi 	collect = RB_LOOKUP(collect_rb_tree, &CollectTree, phys_offset);
4830083f684STomohiro Kusumi 	if (collect)
4846ed4c886SMatthew Dillon 		return(collect);
48595c0f6b0STomohiro Kusumi 
486c8f165e2STomohiro Kusumi 	collect = calloc(1, sizeof(*collect));
487c8f165e2STomohiro Kusumi 	collect->track2 = calloc(1, HAMMER_BIGBLOCK_SIZE);  /* 1<<23 bytes */
488c8f165e2STomohiro Kusumi 	collect->layer2 = calloc(1, HAMMER_BIGBLOCK_SIZE);  /* 1<<23 bytes */
489c8f165e2STomohiro Kusumi 	collect->offsets = calloc(HAMMER_BLOCKMAP_RADIX2, sizeof(hammer_off_t));
4906ed4c886SMatthew Dillon 	collect->phys_offset = phys_offset;
4910083f684STomohiro Kusumi 	RB_INSERT(collect_rb_tree, &CollectTree, collect);
4926ed4c886SMatthew Dillon 
4936ed4c886SMatthew Dillon 	return (collect);
4946ed4c886SMatthew Dillon }
4956ed4c886SMatthew Dillon 
4966ed4c886SMatthew Dillon static
497488d97f5STomohiro Kusumi void
collect_rel(collect_t collect)498488d97f5STomohiro Kusumi collect_rel(collect_t collect)
499488d97f5STomohiro Kusumi {
5005aa4f01cSTomohiro Kusumi 	free(collect->offsets);
501488d97f5STomohiro Kusumi 	free(collect->layer2);
502488d97f5STomohiro Kusumi 	free(collect->track2);
503488d97f5STomohiro Kusumi 	free(collect);
504488d97f5STomohiro Kusumi }
505488d97f5STomohiro Kusumi 
506488d97f5STomohiro Kusumi static
50721e9e7d5STomohiro Kusumi hammer_blockmap_layer2_t
collect_get_track(collect_t collect,hammer_off_t offset,int zone,hammer_blockmap_layer2_t layer2)508901e04c7STomohiro Kusumi collect_get_track(collect_t collect, hammer_off_t offset, int zone,
50921e9e7d5STomohiro Kusumi 		  hammer_blockmap_layer2_t layer2)
5106ed4c886SMatthew Dillon {
51121e9e7d5STomohiro Kusumi 	hammer_blockmap_layer2_t track2;
5126ed4c886SMatthew Dillon 	size_t i;
5136ed4c886SMatthew Dillon 
514f5b0d00fSTomohiro Kusumi 	i = HAMMER_BLOCKMAP_LAYER2_INDEX(offset);
5156ed4c886SMatthew Dillon 	track2 = &collect->track2[i];
5166ed4c886SMatthew Dillon 	if (track2->entry_crc == 0) {
5176ed4c886SMatthew Dillon 		collect->layer2[i] = *layer2;
5185aa4f01cSTomohiro Kusumi 		collect->offsets[i] = offset & ~HAMMER_BIGBLOCK_MASK64;
519901e04c7STomohiro Kusumi 		track2->zone = zone;
520e04ee2deSTomohiro Kusumi 		track2->bytes_free = HAMMER_BIGBLOCK_SIZE;
5216ed4c886SMatthew Dillon 		track2->entry_crc = 1;	/* steal field to tag track load */
5226ed4c886SMatthew Dillon 	}
5236ed4c886SMatthew Dillon 	return (track2);
5246ed4c886SMatthew Dillon }
5256ed4c886SMatthew Dillon 
5266ed4c886SMatthew Dillon static
5276ed4c886SMatthew Dillon void
dump_collect_table(void)5286ed4c886SMatthew Dillon dump_collect_table(void)
5296ed4c886SMatthew Dillon {
53091416fbdSTomohiro Kusumi 	collect_t collect;
53118dbf12fSTomohiro Kusumi 	int error = 0;
53264321bafSTomohiro Kusumi 	zone_stat_t stats = NULL;
533020339d5STomohiro Kusumi 
534020339d5STomohiro Kusumi 	if (VerboseOpt)
535020339d5STomohiro Kusumi 		stats = hammer_init_zone_stat();
5366ed4c886SMatthew Dillon 
5370083f684STomohiro Kusumi 	RB_FOREACH(collect, collect_rb_tree, &CollectTree) {
538d42b45c3STomohiro Kusumi 		dump_collect(collect, stats);
53918dbf12fSTomohiro Kusumi 		error += collect->error;
5400083f684STomohiro Kusumi 	}
5410083f684STomohiro Kusumi 
5420083f684STomohiro Kusumi 	while ((collect = RB_ROOT(&CollectTree)) != NULL) {
5430083f684STomohiro Kusumi 		RB_REMOVE(collect_rb_tree, &CollectTree, collect);
54491416fbdSTomohiro Kusumi 		collect_rel(collect);
5456ed4c886SMatthew Dillon 	}
5460083f684STomohiro Kusumi 	assert(RB_EMPTY(&CollectTree));
547d42b45c3STomohiro Kusumi 
548dd96867bSTomohiro Kusumi 	if (stats) {
549020339d5STomohiro Kusumi 		hammer_print_zone_stat(stats);
550020339d5STomohiro Kusumi 		hammer_cleanup_zone_stat(stats);
551d42b45c3STomohiro Kusumi 	}
55218dbf12fSTomohiro Kusumi 
55352e2f1b5STomohiro Kusumi 	if (num_bad_node || VerboseOpt)
5544a08dcf4STomohiro Kusumi 		printf("%d bad nodes\n", num_bad_node);
55552e2f1b5STomohiro Kusumi 	if (error || VerboseOpt)
55618dbf12fSTomohiro Kusumi 		printf("%d errors\n", error);
5576ed4c886SMatthew Dillon }
5586ed4c886SMatthew Dillon 
5596ed4c886SMatthew Dillon static
5606ed4c886SMatthew Dillon void
dump_collect(collect_t collect,zone_stat_t stats)56164321bafSTomohiro Kusumi dump_collect(collect_t collect, zone_stat_t stats)
5626ed4c886SMatthew Dillon {
56321e9e7d5STomohiro Kusumi 	hammer_blockmap_layer2_t track2;
56421e9e7d5STomohiro Kusumi 	hammer_blockmap_layer2_t layer2;
565901e04c7STomohiro Kusumi 	hammer_off_t offset;
566f540a63dSTomohiro Kusumi 	int i;
5676ed4c886SMatthew Dillon 
5686ed4c886SMatthew Dillon 	for (i = 0; i < HAMMER_BLOCKMAP_RADIX2; ++i) {
5696ed4c886SMatthew Dillon 		track2 = &collect->track2[i];
5706ed4c886SMatthew Dillon 		layer2 = &collect->layer2[i];
5715aa4f01cSTomohiro Kusumi 		offset = collect->offsets[i];
5726ed4c886SMatthew Dillon 
5736ed4c886SMatthew Dillon 		/*
574f8589256STomohiro Kusumi 		 * Check big-blocks referenced by freemap, data,
575f8589256STomohiro Kusumi 		 * B-Tree nodes and UNDO fifo.
5766ed4c886SMatthew Dillon 		 */
5776ed4c886SMatthew Dillon 		if (track2->entry_crc == 0)
5786ed4c886SMatthew Dillon 			continue;
5796ed4c886SMatthew Dillon 
580f254e677STomohiro Kusumi 		if (DebugOpt) {
581f540a63dSTomohiro Kusumi 			assert((layer2->zone == HAMMER_ZONE_UNDO_INDEX) ||
582f540a63dSTomohiro Kusumi 				(layer2->zone == HAMMER_ZONE_FREEMAP_INDEX) ||
583f540a63dSTomohiro Kusumi 				hammer_is_index_record(layer2->zone));
584f254e677STomohiro Kusumi 		}
585dd96867bSTomohiro Kusumi 		if (stats)
586020339d5STomohiro Kusumi 			hammer_add_zone_stat_layer2(stats, layer2);
587d42b45c3STomohiro Kusumi 
588901e04c7STomohiro Kusumi 		if (track2->zone != layer2->zone) {
589850f27eeSTomohiro Kusumi 			printf("BZ\tblock=%016jx calc zone=%-2d, got zone=%-2d\n",
5901f5e0b99SSascha Wildner 				(uintmax_t)offset,
591901e04c7STomohiro Kusumi 				track2->zone,
592901e04c7STomohiro Kusumi 				layer2->zone);
593901e04c7STomohiro Kusumi 			collect->error++;
594901e04c7STomohiro Kusumi 		} else if (track2->bytes_free != layer2->bytes_free) {
595850f27eeSTomohiro Kusumi 			printf("BM\tblock=%016jx zone=%-2d calc %d free, got %d\n",
5961f5e0b99SSascha Wildner 				(uintmax_t)offset,
597d42b45c3STomohiro Kusumi 				layer2->zone,
5986ed4c886SMatthew Dillon 				track2->bytes_free,
5996ed4c886SMatthew Dillon 				layer2->bytes_free);
60018dbf12fSTomohiro Kusumi 			collect->error++;
6016ed4c886SMatthew Dillon 		} else if (VerboseOpt) {
602850f27eeSTomohiro Kusumi 			printf("\tblock=%016jx zone=%-2d %d free (correct)\n",
6031f5e0b99SSascha Wildner 				(uintmax_t)offset,
604d42b45c3STomohiro Kusumi 				layer2->zone,
6056ed4c886SMatthew Dillon 				track2->bytes_free);
6066ed4c886SMatthew Dillon 		}
6076ed4c886SMatthew Dillon 	}
6086ed4c886SMatthew Dillon }
609