/* * checkhammer.c * * checkhammer blockmapdump btreedump */ #include #include #include #include #include #include struct rbmap_tree; struct rbmap; static void parseBlockMap(FILE *fp); static void parseBTree(FILE *fp); static void dumpResults(void); static int rbmap_cmp(struct rbmap *, struct rbmap *); typedef u_int64_t hammer_off_t; typedef struct rbmap *rbmap_t; RB_HEAD(rbmap_tree, rbmap); RB_PROTOTYPE2(rbmap_tree, rbmap, rbentry, rbmap_cmp, hammer_off_t); struct rbmap { RB_ENTRY(rbmap) rbentry; hammer_off_t base; long app; long free; long bytes; int zone; }; RB_GENERATE2(rbmap_tree, rbmap, rbentry, rbmap_cmp, hammer_off_t, base); struct rbmap_tree rbroot; static int rbmap_cmp(struct rbmap *rb1, struct rbmap *rb2) { if (rb1->base < rb2->base) return(-1); if (rb1->base > rb2->base) return(1); return(0); } int main(int ac, char **av) { FILE *fp; if (ac != 3) { fprintf(stderr, "checkhammer blockmapdump btreedump\n"); exit(1); } if ((fp = fopen(av[1], "r")) == NULL) { fprintf(stderr, "Unable to open %s\n", av[1]); exit(1); } RB_INIT(&rbroot); parseBlockMap(fp); fclose(fp); if ((fp = fopen(av[2], "r")) == NULL) { fprintf(stderr, "Unable to open %s\n", av[1]); exit(1); } parseBTree(fp); fclose(fp); dumpResults(); return(0); } static void parseBlockMap(FILE *fp) { char buf[1024]; rbmap_t map; int zone; long long base; long long app; long long free; while (fgets(buf, sizeof(buf), fp) != NULL) { if (sscanf(buf, " 4%llx zone=%d app=%lld free=%lld", &base, &zone, &app, &free) != 4) continue; if (RB_LOOKUP(rbmap_tree, &rbroot, (hammer_off_t)base)) continue; map = malloc(sizeof(*map)); map->base = (hammer_off_t)base; map->app = (long)app; map->free = (long)free; map->zone = zone; map->bytes = 0; RB_INSERT(rbmap_tree, &rbroot, map); } } static void parseBTree(FILE *fp) { char buf[1024]; rbmap_t map; long long base; long long bytes; while (fgets(buf, sizeof(buf), fp) != NULL) { if (sscanf(buf, " NODE 8%llx", &base) == 1) { base &= 0x0FFFFFFFFF800000LLU; map = RB_LOOKUP(rbmap_tree, &rbroot, base); if (map == NULL) { printf("(not in blockmap): %s", buf); continue; } map->bytes += 4096; } if (sscanf(buf, " dataoff=%llx/%lld", &base, &bytes) == 2) { base &= 0x0FFFFFFFFF800000LLU; map = RB_LOOKUP(rbmap_tree, &rbroot, base); if (map == NULL) { printf("(not in blockmap): %s", buf); continue; } map->bytes += (bytes + 15) & ~15; } } } static void dumpResults(void) { rbmap_t map; hammer_off_t bfree; printf("mismatches: (blockmap, actual)\n"); RB_FOREACH(map, rbmap_tree, &rbroot) { bfree = 8192 * 1024 - (int64_t)map->bytes; /* * Ignore matches */ if (map->free == bfree) continue; /* * If the block is completely allocated but our calculations * show nobody is referencing it it is probably an undo, * blockmap, or unavailable reserved area. */ if (map->free == 0 && bfree == 8192 * 1024) { if (map->zone == 3 || map->zone == 4 || map->zone == 15) continue; } printf(" bmap %016jx %jd %jd\n", map->base, (intmax_t)(int64_t)map->free, (intmax_t)(int64_t)bfree); } }