1 /* 2 * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sbin/hammer/cmd_blockmap.c,v 1.4 2008/07/19 18:48:14 dillon Exp $ 35 */ 36 37 #include "hammer.h" 38 39 typedef struct collect { 40 struct collect *hnext; 41 hammer_off_t phys_offset; 42 struct hammer_blockmap_layer2 *track2; 43 struct hammer_blockmap_layer2 *layer2; 44 } *collect_t; 45 46 #define COLLECT_HSIZE 1024 47 #define COLLECT_HMASK (COLLECT_HSIZE - 1) 48 49 collect_t CollectHash[COLLECT_HSIZE]; 50 51 static void dump_blockmap(const char *label, int zone); 52 static void check_btree_node(hammer_off_t node_offset, int depth); 53 static void collect_btree_elm(hammer_btree_elm_t elm); 54 static struct hammer_blockmap_layer2 *collect_get_track( 55 collect_t collect, hammer_off_t offset, 56 struct hammer_blockmap_layer2 *layer2); 57 static collect_t collect_get(hammer_off_t phys_offset); 58 static void dump_collect_table(void); 59 static void dump_collect(collect_t collect); 60 61 void 62 hammer_cmd_blockmap(void) 63 { 64 dump_blockmap("btree", HAMMER_ZONE_FREEMAP_INDEX); 65 } 66 67 static 68 void 69 dump_blockmap(const char *label, int zone) 70 { 71 struct volume_info *root_volume; 72 hammer_blockmap_t rootmap; 73 struct hammer_blockmap_layer1 *layer1; 74 struct hammer_blockmap_layer2 *layer2; 75 struct buffer_info *buffer1 = NULL; 76 struct buffer_info *buffer2 = NULL; 77 hammer_off_t layer1_offset; 78 hammer_off_t layer2_offset; 79 hammer_off_t scan1; 80 hammer_off_t scan2; 81 int xerr; 82 83 assert(RootVolNo >= 0); 84 root_volume = get_volume(RootVolNo); 85 rootmap = &root_volume->ondisk->vol0_blockmap[zone]; 86 assert(rootmap->phys_offset != 0); 87 88 printf("zone %-16s next %016jx alloc %016jx\n", 89 label, 90 (uintmax_t)rootmap->next_offset, 91 (uintmax_t)rootmap->alloc_offset); 92 93 for (scan1 = HAMMER_ZONE_ENCODE(zone, 0); 94 scan1 < HAMMER_ZONE_ENCODE(zone, HAMMER_OFF_LONG_MASK); 95 scan1 += HAMMER_BLOCKMAP_LAYER2) { 96 /* 97 * Dive layer 1. 98 */ 99 layer1_offset = rootmap->phys_offset + 100 HAMMER_BLOCKMAP_LAYER1_OFFSET(scan1); 101 layer1 = get_buffer_data(layer1_offset, &buffer1, 0); 102 xerr = ' '; 103 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE)) 104 xerr = 'B'; 105 if (xerr == ' ' && 106 layer1->phys_offset == HAMMER_BLOCKMAP_UNAVAIL) { 107 continue; 108 } 109 printf("%c layer1 %016jx @%016jx blocks-free %jd\n", 110 xerr, 111 (uintmax_t)scan1, 112 (uintmax_t)layer1->phys_offset, 113 (intmax_t)layer1->blocks_free); 114 if (layer1->phys_offset == HAMMER_BLOCKMAP_FREE) 115 continue; 116 for (scan2 = scan1; 117 scan2 < scan1 + HAMMER_BLOCKMAP_LAYER2; 118 scan2 += HAMMER_LARGEBLOCK_SIZE 119 ) { 120 /* 121 * Dive layer 2, each entry represents a large-block. 122 */ 123 layer2_offset = layer1->phys_offset + 124 HAMMER_BLOCKMAP_LAYER2_OFFSET(scan2); 125 layer2 = get_buffer_data(layer2_offset, &buffer2, 0); 126 xerr = ' '; 127 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE)) 128 xerr = 'B'; 129 printf("%c %016jx zone=%d app=%-7d free=%-7d\n", 130 xerr, 131 (uintmax_t)scan2, 132 layer2->zone, 133 layer2->append_off, 134 layer2->bytes_free); 135 } 136 } 137 if (buffer1) 138 rel_buffer(buffer1); 139 if (buffer2) 140 rel_buffer(buffer2); 141 rel_volume(root_volume); 142 } 143 144 void 145 hammer_cmd_checkmap(void) 146 { 147 struct volume_info *volume; 148 hammer_off_t node_offset; 149 150 volume = get_volume(RootVolNo); 151 node_offset = volume->ondisk->vol0_btree_root; 152 if (QuietOpt < 3) { 153 printf("Volume header\trecords=%jd next_tid=%016jx\n", 154 (intmax_t)volume->ondisk->vol0_stat_records, 155 (uintmax_t)volume->ondisk->vol0_next_tid); 156 printf("\t\tbufoffset=%016jx\n", 157 (uintmax_t)volume->ondisk->vol_buf_beg); 158 } 159 rel_volume(volume); 160 161 printf("Collecting allocation info from B-Tree: "); 162 fflush(stdout); 163 check_btree_node(node_offset, 0); 164 printf("done\n"); 165 dump_collect_table(); 166 } 167 168 static void 169 check_btree_node(hammer_off_t node_offset, int depth) 170 { 171 struct buffer_info *buffer = NULL; 172 hammer_node_ondisk_t node; 173 hammer_btree_elm_t elm; 174 int i; 175 char badc; 176 177 node = get_node(node_offset, &buffer); 178 179 if (crc32(&node->crc + 1, HAMMER_BTREE_CRCSIZE) == node->crc) 180 badc = ' '; 181 else 182 badc = 'B'; 183 184 if (badc != ' ') { 185 printf("B NODE %016jx cnt=%02d p=%016jx " 186 "type=%c depth=%d", 187 (uintmax_t)node_offset, node->count, 188 (uintmax_t)node->parent, 189 (node->type ? node->type : '?'), depth); 190 printf(" mirror %016jx", (uintmax_t)node->mirror_tid); 191 printf(" {\n"); 192 } 193 194 for (i = 0; i < node->count; ++i) { 195 elm = &node->elms[i]; 196 197 switch(node->type) { 198 case HAMMER_BTREE_TYPE_INTERNAL: 199 if (elm->internal.subtree_offset) { 200 check_btree_node(elm->internal.subtree_offset, 201 depth + 1); 202 } 203 break; 204 case HAMMER_BTREE_TYPE_LEAF: 205 if (elm->leaf.data_offset) 206 collect_btree_elm(elm); 207 break; 208 default: 209 assert(0); 210 } 211 } 212 rel_buffer(buffer); 213 } 214 215 static 216 void 217 collect_btree_elm(hammer_btree_elm_t elm) 218 { 219 struct hammer_blockmap_layer1 layer1; 220 struct hammer_blockmap_layer2 layer2; 221 struct hammer_blockmap_layer2 *track2; 222 hammer_off_t offset = elm->leaf.data_offset; 223 collect_t collect; 224 int error; 225 226 blockmap_lookup(offset, &layer1, &layer2, &error); 227 collect = collect_get(layer1.phys_offset); 228 track2 = collect_get_track(collect, offset, &layer2); 229 track2->bytes_free -= (elm->leaf.data_len + 15) & ~15; 230 } 231 232 static 233 collect_t 234 collect_get(hammer_off_t phys_offset) 235 { 236 int hv = crc32(&phys_offset, sizeof(phys_offset)) & COLLECT_HMASK; 237 collect_t collect; 238 239 for (collect = CollectHash[hv]; collect; collect = collect->hnext) { 240 if (collect->phys_offset == phys_offset) 241 return(collect); 242 } 243 collect = calloc(sizeof(*collect), 1); 244 collect->track2 = malloc(HAMMER_LARGEBLOCK_SIZE); 245 collect->layer2 = malloc(HAMMER_LARGEBLOCK_SIZE); 246 collect->phys_offset = phys_offset; 247 collect->hnext = CollectHash[hv]; 248 CollectHash[hv] = collect; 249 bzero(collect->track2, HAMMER_LARGEBLOCK_SIZE); 250 bzero(collect->layer2, HAMMER_LARGEBLOCK_SIZE); 251 252 return (collect); 253 } 254 255 static 256 struct hammer_blockmap_layer2 * 257 collect_get_track(collect_t collect, hammer_off_t offset, 258 struct hammer_blockmap_layer2 *layer2) 259 { 260 struct hammer_blockmap_layer2 *track2; 261 size_t i; 262 263 i = HAMMER_BLOCKMAP_LAYER2_OFFSET(offset) / sizeof(*track2); 264 track2 = &collect->track2[i]; 265 if (track2->entry_crc == 0) { 266 collect->layer2[i] = *layer2; 267 track2->bytes_free = HAMMER_LARGEBLOCK_SIZE; 268 track2->entry_crc = 1; /* steal field to tag track load */ 269 } 270 return (track2); 271 } 272 273 static 274 void 275 dump_collect_table(void) 276 { 277 collect_t collect; 278 int i; 279 280 for (i = 0; i < COLLECT_HSIZE; ++i) { 281 for (collect = CollectHash[i]; 282 collect; 283 collect = collect->hnext) { 284 dump_collect(collect); 285 } 286 } 287 } 288 289 static 290 void 291 dump_collect(collect_t collect) 292 { 293 struct hammer_blockmap_layer2 *track2; 294 struct hammer_blockmap_layer2 *layer2; 295 size_t i; 296 297 for (i = 0; i < HAMMER_BLOCKMAP_RADIX2; ++i) { 298 track2 = &collect->track2[i]; 299 layer2 = &collect->layer2[i]; 300 301 /* 302 * Currently just check bigblocks referenced by data 303 * or B-Tree nodes. 304 */ 305 if (track2->entry_crc == 0) 306 continue; 307 308 if (track2->bytes_free != layer2->bytes_free) { 309 printf("BM\tblock=%016jx calc %d free, got %d\n", 310 (intmax_t)(collect->phys_offset + 311 i * HAMMER_LARGEBLOCK_SIZE), 312 track2->bytes_free, 313 layer2->bytes_free); 314 } else if (VerboseOpt) { 315 printf("\tblock=%016jx %d free (correct)\n", 316 (intmax_t)(collect->phys_offset + 317 i * HAMMER_LARGEBLOCK_SIZE), 318 track2->bytes_free); 319 } 320 } 321 } 322