1 /* 2 * checkhammer.c 3 * 4 * checkhammer blockmapdump btreedump 5 */ 6 7 #include <sys/types.h> 8 #include <sys/tree.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <unistd.h> 12 #include <string.h> 13 14 struct rbmap_tree; 15 struct rbmap; 16 17 static void parseBlockMap(FILE *fp); 18 static void parseBTree(FILE *fp); 19 static void dumpResults(void); 20 static int rbmap_cmp(struct rbmap *, struct rbmap *); 21 22 typedef u_int64_t hammer_off_t; 23 typedef struct rbmap *rbmap_t; 24 25 RB_HEAD(rbmap_tree, rbmap); 26 RB_PROTOTYPE2(rbmap_tree, rbmap, rbentry, rbmap_cmp, hammer_off_t); 27 28 struct rbmap { 29 RB_ENTRY(rbmap) rbentry; 30 hammer_off_t base; 31 long app; 32 long free; 33 long bytes; 34 int zone; 35 }; 36 37 RB_GENERATE2(rbmap_tree, rbmap, rbentry, rbmap_cmp, hammer_off_t, base); 38 39 struct rbmap_tree rbroot; 40 41 static 42 int 43 rbmap_cmp(struct rbmap *rb1, struct rbmap *rb2) 44 { 45 if (rb1->base < rb2->base) 46 return(-1); 47 if (rb1->base > rb2->base) 48 return(1); 49 return(0); 50 } 51 52 int 53 main(int ac, char **av) 54 { 55 FILE *fp; 56 57 if (ac != 3) { 58 fprintf(stderr, "checkhammer blockmapdump btreedump\n"); 59 exit(1); 60 } 61 if ((fp = fopen(av[1], "r")) == NULL) { 62 fprintf(stderr, "Unable to open %s\n", av[1]); 63 exit(1); 64 } 65 66 RB_INIT(&rbroot); 67 parseBlockMap(fp); 68 fclose(fp); 69 if ((fp = fopen(av[2], "r")) == NULL) { 70 fprintf(stderr, "Unable to open %s\n", av[1]); 71 exit(1); 72 } 73 parseBTree(fp); 74 fclose(fp); 75 76 dumpResults(); 77 return(0); 78 } 79 80 static void 81 parseBlockMap(FILE *fp) 82 { 83 char buf[1024]; 84 rbmap_t map; 85 int zone; 86 long long base; 87 long long app; 88 long long free; 89 90 while (fgets(buf, sizeof(buf), fp) != NULL) { 91 if (sscanf(buf, " 4%llx zone=%d app=%lld free=%lld", 92 &base, &zone, &app, &free) != 4) 93 continue; 94 if (RB_LOOKUP(rbmap_tree, &rbroot, (hammer_off_t)base)) 95 continue; 96 map = malloc(sizeof(*map)); 97 map->base = (hammer_off_t)base; 98 map->app = (long)app; 99 map->free = (long)free; 100 map->zone = zone; 101 map->bytes = 0; 102 RB_INSERT(rbmap_tree, &rbroot, map); 103 } 104 } 105 106 static void 107 parseBTree(FILE *fp) 108 { 109 char buf[1024]; 110 rbmap_t map; 111 long long base; 112 long long bytes; 113 114 while (fgets(buf, sizeof(buf), fp) != NULL) { 115 if (sscanf(buf, " NODE 8%llx", &base) == 1) { 116 base &= 0x0FFFFFFFFF800000LLU; 117 map = RB_LOOKUP(rbmap_tree, &rbroot, base); 118 if (map == NULL) { 119 printf("(not in blockmap): %s", buf); 120 continue; 121 } 122 map->bytes += 4096; 123 } 124 if (sscanf(buf, " dataoff=%llx/%lld", 125 &base, &bytes) == 2) { 126 base &= 0x0FFFFFFFFF800000LLU; 127 map = RB_LOOKUP(rbmap_tree, &rbroot, base); 128 if (map == NULL) { 129 printf("(not in blockmap): %s", buf); 130 continue; 131 } 132 map->bytes += (bytes + 15) & ~15; 133 } 134 } 135 } 136 137 static void 138 dumpResults(void) 139 { 140 rbmap_t map; 141 hammer_off_t bfree; 142 143 printf("mismatches: (blockmap, actual)\n"); 144 RB_FOREACH(map, rbmap_tree, &rbroot) { 145 bfree = 8192 * 1024 - (int64_t)map->bytes; 146 147 /* 148 * Ignore matches 149 */ 150 if (map->free == bfree) 151 continue; 152 153 /* 154 * If the block is completely allocated but our calculations 155 * show nobody is referencing it it is probably an undo, 156 * blockmap, or unavailable reserved area. 157 */ 158 if (map->free == 0 && bfree == 8192 * 1024) { 159 if (map->zone == 3 || map->zone == 4 || 160 map->zone == 15) 161 continue; 162 } 163 164 printf(" bmap %016jx %jd %jd\n", 165 map->base, 166 (intmax_t)(int64_t)map->free, 167 (intmax_t)(int64_t)bfree); 168 } 169 } 170