2 * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
3 * Copyright (c) 2019 The DragonFly Project
6 * This code is derived from software contributed to The DragonFly Project
7 * by Matthew Dillon <dillon@dragonflybsd.org>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
19 * 3. Neither the name of The DragonFly Project nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific, prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <sys/types.h>
40 #include <sys/queue.h>
41 #include <sys/ttycom.h>
51 #include <openssl/sha.h>
53 #include <vfs/hammer2/hammer2_disk.h>
54 #include <vfs/hammer2/hammer2_xxhash.h>
56 #include "hammer2_subs.h"
57 #include "fsck_hammer2.h"
60 TAILQ_ENTRY(blockref_msg) entry;
61 hammer2_blockref_t bref;
65 TAILQ_HEAD(blockref_list, blockref_msg);
67 struct blockref_entry {
68 RB_ENTRY(blockref_entry) entry;
69 hammer2_off_t data_off;
70 struct blockref_list head;
74 blockref_cmp(struct blockref_entry *b1, struct blockref_entry *b2)
76 if (b1->data_off < b2->data_off)
78 if (b1->data_off > b2->data_off)
83 RB_HEAD(blockref_tree, blockref_entry);
84 RB_PROTOTYPE2(blockref_tree, blockref_entry, entry, blockref_cmp,
86 RB_GENERATE2(blockref_tree, blockref_entry, entry, blockref_cmp, hammer2_off_t,
90 struct blockref_tree root;
91 uint8_t type; /* HAMMER2_BREF_TYPE_VOLUME or FREEMAP */
92 uint64_t total_blockref;
94 uint64_t total_invalid;
97 /* use volume or freemap depending on type value */
100 uint64_t total_indirect;
102 uint64_t total_dirent;
105 uint64_t total_freemap_node;
106 uint64_t total_freemap_leaf;
111 static void print_blockref_entry(int, struct blockref_tree *);
112 static void init_blockref_stats(blockref_stats_t *, uint8_t);
113 static void cleanup_blockref_stats(blockref_stats_t *);
114 static void print_blockref_stats(const blockref_stats_t *, bool);
115 static int verify_volume_header(const hammer2_volume_data_t *);
116 static int read_media(int, const hammer2_blockref_t *, hammer2_media_data_t *,
118 static int verify_blockref(int, const hammer2_volume_data_t *,
119 const hammer2_blockref_t *, bool, blockref_stats_t *);
120 static int init_pfs_blockref(int, const hammer2_volume_data_t *,
121 const hammer2_blockref_t *, struct blockref_list *);
122 static void cleanup_pfs_blockref(struct blockref_list *);
123 static void print_media(FILE *, int, const hammer2_blockref_t *,
124 hammer2_media_data_t *, size_t);
125 static const char* hammer2_blockref_to_str(uint8_t);
127 static int best_zone = -1;
132 tfprintf(FILE *fp, int tab, const char *ctl, ...)
137 ret = fprintf(fp, "%*s", tab * TAB, "");
142 vfprintf(fp, ctl, va);
147 tsnprintf(char *str, size_t siz, int tab, const char *ctl, ...)
152 ret = snprintf(str, siz, "%*s", tab * TAB, "");
153 if (ret < 0 || ret >= (int)siz)
157 vsnprintf(str + ret, siz, ctl, va);
162 tprintf_zone(int tab, int i, const hammer2_blockref_t *bref)
164 tfprintf(stdout, tab, "zone.%d %016jx%s\n",
165 i, (uintmax_t)bref->data_off,
166 (!ScanBest && i == best_zone) ? " (best)" : "");
170 init_root_blockref(int fd, int i, uint8_t type, hammer2_blockref_t *bref)
172 assert(type == HAMMER2_BREF_TYPE_EMPTY ||
173 type == HAMMER2_BREF_TYPE_VOLUME ||
174 type == HAMMER2_BREF_TYPE_FREEMAP);
175 memset(bref, 0, sizeof(*bref));
177 bref->data_off = (i * HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX;
179 lseek(fd, bref->data_off & ~HAMMER2_OFF_MASK_RADIX, SEEK_SET);
183 find_best_zone(int fd)
185 hammer2_blockref_t best;
188 memset(&best, 0, sizeof(best));
190 for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) {
191 hammer2_volume_data_t voldata;
192 hammer2_blockref_t broot;
195 init_root_blockref(fd, i, HAMMER2_BREF_TYPE_EMPTY, &broot);
196 ret = read(fd, &voldata, HAMMER2_PBUFSIZE);
197 if (ret == HAMMER2_PBUFSIZE) {
198 if ((voldata.magic != HAMMER2_VOLUME_ID_HBO) &&
199 (voldata.magic != HAMMER2_VOLUME_ID_ABO))
201 broot.mirror_tid = voldata.mirror_tid;
202 if (best_i < 0 || best.mirror_tid < broot.mirror_tid) {
206 } else if (ret == -1) {
210 tfprintf(stderr, 1, "Failed to read volume header\n");
219 test_volume_header(int fd)
224 for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) {
225 hammer2_volume_data_t voldata;
226 hammer2_blockref_t broot;
229 if (ScanBest && i != best_zone)
231 init_root_blockref(fd, i, HAMMER2_BREF_TYPE_EMPTY, &broot);
232 ret = read(fd, &voldata, HAMMER2_PBUFSIZE);
233 if (ret == HAMMER2_PBUFSIZE) {
234 tprintf_zone(0, i, &broot);
235 if (verify_volume_header(&voldata) == -1)
237 } else if (ret == -1) {
241 tfprintf(stderr, 1, "Failed to read volume header\n");
246 return failed ? -1 : 0;
250 test_blockref(int fd, uint8_t type)
255 for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) {
256 hammer2_volume_data_t voldata;
257 hammer2_blockref_t broot;
260 if (ScanBest && i != best_zone)
262 init_root_blockref(fd, i, type, &broot);
263 ret = read(fd, &voldata, HAMMER2_PBUFSIZE);
264 if (ret == HAMMER2_PBUFSIZE) {
265 blockref_stats_t bstats;
266 init_blockref_stats(&bstats, type);
267 tprintf_zone(0, i, &broot);
268 if (verify_blockref(fd, &voldata, &broot, false,
271 print_blockref_stats(&bstats, true);
272 print_blockref_entry(fd, &bstats.root);
273 cleanup_blockref_stats(&bstats);
274 } else if (ret == -1) {
278 tfprintf(stderr, 1, "Failed to read volume header\n");
283 return failed ? -1 : 0;
287 test_pfs_blockref(int fd, const char *name)
289 uint8_t type = HAMMER2_BREF_TYPE_VOLUME;
293 for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) {
294 hammer2_volume_data_t voldata;
295 hammer2_blockref_t broot;
298 if (ScanBest && i != best_zone)
300 init_root_blockref(fd, i, type, &broot);
301 ret = read(fd, &voldata, HAMMER2_PBUFSIZE);
302 if (ret == HAMMER2_PBUFSIZE) {
303 struct blockref_list blist;
304 struct blockref_msg *p;
307 tprintf_zone(0, i, &broot);
309 if (init_pfs_blockref(fd, &voldata, &broot, &blist) ==
311 tfprintf(stderr, 1, "Failed to read PFS "
316 if (TAILQ_EMPTY(&blist)) {
317 tfprintf(stderr, 1, "Failed to find PFS "
322 TAILQ_FOREACH(p, &blist, entry) {
323 blockref_stats_t bstats;
324 if (name && strcmp(name, p->msg))
327 tfprintf(stdout, 1, "%s\n", p->msg);
328 init_blockref_stats(&bstats, type);
329 if (verify_blockref(fd, &voldata, &p->bref,
330 false, &bstats) == -1)
332 print_blockref_stats(&bstats, true);
333 print_blockref_entry(fd, &bstats.root);
334 cleanup_blockref_stats(&bstats);
336 cleanup_pfs_blockref(&blist);
337 if (name && !count) {
338 tfprintf(stderr, 1, "PFS \"%s\" not found\n",
342 } else if (ret == -1) {
346 tfprintf(stderr, 1, "Failed to read volume header\n");
351 return failed ? -1 : 0;
362 if (ioctl(0, TIOCGWINSZ, &ws) != -1)
364 if (columns == 0 && (cp = getenv("COLUMNS")))
367 columns = 80; /* last resort */
373 cleanup_blockref_msg(struct blockref_list *head)
375 struct blockref_msg *p;
377 while ((p = TAILQ_FIRST(head)) != NULL) {
378 TAILQ_REMOVE(head, p, entry);
382 assert(TAILQ_EMPTY(head));
386 cleanup_blockref_entry(struct blockref_tree *root)
388 struct blockref_entry *e;
390 while ((e = RB_ROOT(root)) != NULL) {
391 RB_REMOVE(blockref_tree, root, e);
392 cleanup_blockref_msg(&e->head);
395 assert(RB_EMPTY(root));
399 add_blockref_msg(struct blockref_list *head, const hammer2_blockref_t *bref,
402 struct blockref_msg *m;
404 m = calloc(1, sizeof(*m));
407 m->msg = strdup(msg);
409 TAILQ_INSERT_TAIL(head, m, entry);
413 add_blockref_entry(struct blockref_tree *root, const hammer2_blockref_t *bref,
416 struct blockref_entry *e;
418 e = RB_LOOKUP(blockref_tree, root, bref->data_off);
420 e = calloc(1, sizeof(*e));
422 TAILQ_INIT(&e->head);
423 e->data_off = bref->data_off;
426 add_blockref_msg(&e->head, bref, msg);
428 RB_INSERT(blockref_tree, root, e);
432 print_blockref_msg(int fd, struct blockref_list *head)
434 struct blockref_msg *m;
436 TAILQ_FOREACH(m, head, entry) {
437 hammer2_blockref_t *bref = &m->bref;
438 hammer2_media_data_t media;
440 tfprintf(stderr, 1, "%016jx %-12s %016jx/%-2d \"%s\"\n",
441 (uintmax_t)bref->data_off,
442 hammer2_blockref_to_str(bref->type),
443 (uintmax_t)bref->key,
447 if (fd != -1 && VerboseOpt > 0) {
449 if (!read_media(fd, bref, &media, &bytes))
450 print_media(stderr, 2, bref, &media, bytes);
452 tfprintf(stderr, 2, "Failed to read media\n");
458 print_blockref_entry(int fd, struct blockref_tree *root)
460 struct blockref_entry *e;
462 RB_FOREACH(e, blockref_tree, root)
463 print_blockref_msg(fd, &e->head);
467 init_blockref_stats(blockref_stats_t *bstats, uint8_t type)
469 memset(bstats, 0, sizeof(*bstats));
470 RB_INIT(&bstats->root);
475 cleanup_blockref_stats(blockref_stats_t *bstats)
477 cleanup_blockref_entry(&bstats->root);
481 print_blockref_stats(const blockref_stats_t *bstats, bool newline)
483 size_t siz = charsperline();
484 char *buf = calloc(1, siz);
488 switch (bstats->type) {
489 case HAMMER2_BREF_TYPE_VOLUME:
490 tsnprintf(buf, siz, 1, "%ju blockref (%ju inode, %ju indirect, "
491 "%ju data, %ju dirent, %ju empty), %s",
492 (uintmax_t)bstats->total_blockref,
493 (uintmax_t)bstats->volume.total_inode,
494 (uintmax_t)bstats->volume.total_indirect,
495 (uintmax_t)bstats->volume.total_data,
496 (uintmax_t)bstats->volume.total_dirent,
497 (uintmax_t)bstats->total_empty,
498 sizetostr(bstats->total_bytes));
500 case HAMMER2_BREF_TYPE_FREEMAP:
501 tsnprintf(buf, siz, 1, "%ju blockref (%ju node, %ju leaf, "
503 (uintmax_t)bstats->total_blockref,
504 (uintmax_t)bstats->freemap.total_freemap_node,
505 (uintmax_t)bstats->freemap.total_freemap_leaf,
506 (uintmax_t)bstats->total_empty,
507 sizetostr(bstats->total_bytes));
524 verify_volume_header(const hammer2_volume_data_t *voldata)
526 hammer2_crc32_t crc0, crc1;
527 const char *p = (const char*)voldata;
529 if ((voldata->magic != HAMMER2_VOLUME_ID_HBO) &&
530 (voldata->magic != HAMMER2_VOLUME_ID_ABO)) {
531 tfprintf(stderr, 1, "Bad magic %jX\n", voldata->magic);
535 if (voldata->magic == HAMMER2_VOLUME_ID_ABO)
536 tfprintf(stderr, 1, "Reverse endian\n");
538 crc0 = voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT0];
539 crc1 = hammer2_icrc32(p + HAMMER2_VOLUME_ICRC0_OFF,
540 HAMMER2_VOLUME_ICRC0_SIZE);
542 tfprintf(stderr, 1, "Bad HAMMER2_VOL_ICRC_SECT0 CRC\n");
546 crc0 = voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT1];
547 crc1 = hammer2_icrc32(p + HAMMER2_VOLUME_ICRC1_OFF,
548 HAMMER2_VOLUME_ICRC1_SIZE);
550 tfprintf(stderr, 1, "Bad HAMMER2_VOL_ICRC_SECT1 CRC\n");
554 crc0 = voldata->icrc_volheader;
555 crc1 = hammer2_icrc32(p + HAMMER2_VOLUME_ICRCVH_OFF,
556 HAMMER2_VOLUME_ICRCVH_SIZE);
558 tfprintf(stderr, 1, "Bad volume header CRC\n");
566 read_media(int fd, const hammer2_blockref_t *bref, hammer2_media_data_t *media,
569 hammer2_off_t io_off, io_base;
570 size_t bytes, io_bytes, boff;
572 bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX);
574 bytes = (size_t)1 << bytes;
576 *media_bytes = bytes;
581 io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX;
582 io_base = io_off & ~(hammer2_off_t)(HAMMER2_MINIOSIZE - 1);
583 boff = io_off - io_base;
585 io_bytes = HAMMER2_MINIOSIZE;
586 while (io_bytes + boff < bytes)
589 if (io_bytes > sizeof(*media))
591 lseek(fd, io_base, SEEK_SET);
592 if (read(fd, media, io_bytes) != (ssize_t)io_bytes)
595 memcpy(media, (char *)media + boff, bytes);
601 verify_blockref(int fd, const hammer2_volume_data_t *voldata,
602 const hammer2_blockref_t *bref, bool norecurse, blockref_stats_t *bstats)
604 hammer2_media_data_t media;
605 hammer2_blockref_t *bscan;
615 uint8_t digest[SHA256_DIGEST_LENGTH];
616 uint64_t digest64[SHA256_DIGEST_LENGTH/8];
619 bstats->total_blockref++;
621 switch (bref->type) {
622 case HAMMER2_BREF_TYPE_EMPTY:
623 bstats->total_empty++;
625 case HAMMER2_BREF_TYPE_INODE:
626 bstats->volume.total_inode++;
628 case HAMMER2_BREF_TYPE_INDIRECT:
629 bstats->volume.total_indirect++;
631 case HAMMER2_BREF_TYPE_DATA:
632 bstats->volume.total_data++;
634 case HAMMER2_BREF_TYPE_DIRENT:
635 bstats->volume.total_dirent++;
637 case HAMMER2_BREF_TYPE_FREEMAP_NODE:
638 bstats->freemap.total_freemap_node++;
640 case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
641 bstats->freemap.total_freemap_leaf++;
643 case HAMMER2_BREF_TYPE_VOLUME:
644 bstats->total_blockref--;
646 case HAMMER2_BREF_TYPE_FREEMAP:
647 bstats->total_blockref--;
650 bstats->total_invalid++;
651 snprintf(msg, sizeof(msg), "Invalid blockref type %d",
653 add_blockref_entry(&bstats->root, bref, msg);
658 switch (read_media(fd, bref, &media, &bytes)) {
660 add_blockref_entry(&bstats->root, bref, "Bad I/O bytes");
663 add_blockref_entry(&bstats->root, bref, "Failed to read media");
669 if (bref->type != HAMMER2_BREF_TYPE_VOLUME &&
670 bref->type != HAMMER2_BREF_TYPE_FREEMAP)
671 bstats->total_bytes += bytes;
673 if (QuietOpt <= 0 && (bstats->total_blockref % 100) == 0)
674 print_blockref_stats(bstats, false);
679 switch (HAMMER2_DEC_CHECK(bref->methods)) {
680 case HAMMER2_CHECK_ISCSI32:
681 cv = hammer2_icrc32(&media, bytes);
682 if (bref->check.iscsi32.value != cv) {
683 add_blockref_entry(&bstats->root, bref,
684 "Bad HAMMER2_CHECK_ISCSI32");
688 case HAMMER2_CHECK_XXHASH64:
689 cv64 = XXH64(&media, bytes, XXH_HAMMER2_SEED);
690 if (bref->check.xxhash64.value != cv64) {
691 add_blockref_entry(&bstats->root, bref,
692 "Bad HAMMER2_CHECK_XXHASH64");
696 case HAMMER2_CHECK_SHA192:
697 SHA256_Init(&hash_ctx);
698 SHA256_Update(&hash_ctx, &media, bytes);
699 SHA256_Final(u.digest, &hash_ctx);
700 u.digest64[2] ^= u.digest64[3];
701 if (memcmp(u.digest, bref->check.sha192.data,
702 sizeof(bref->check.sha192.data))) {
703 add_blockref_entry(&bstats->root, bref,
704 "Bad HAMMER2_CHECK_SHA192");
708 case HAMMER2_CHECK_FREEMAP:
709 cv = hammer2_icrc32(&media, bytes);
710 if (bref->check.freemap.icrc32 != cv) {
711 add_blockref_entry(&bstats->root, bref,
712 "Bad HAMMER2_CHECK_FREEMAP");
718 switch (bref->type) {
719 case HAMMER2_BREF_TYPE_INODE:
720 if (!(media.ipdata.meta.op_flags & HAMMER2_OPFLAG_DIRECTDATA)) {
721 bscan = &media.ipdata.u.blockset.blockref[0];
722 bcount = HAMMER2_SET_COUNT;
728 case HAMMER2_BREF_TYPE_INDIRECT:
729 bscan = &media.npdata[0];
730 bcount = bytes / sizeof(hammer2_blockref_t);
732 case HAMMER2_BREF_TYPE_FREEMAP_NODE:
733 bscan = &media.npdata[0];
734 bcount = bytes / sizeof(hammer2_blockref_t);
736 case HAMMER2_BREF_TYPE_VOLUME:
737 bscan = &media.voldata.sroot_blockset.blockref[0];
738 bcount = HAMMER2_SET_COUNT;
740 case HAMMER2_BREF_TYPE_FREEMAP:
741 bscan = &media.voldata.freemap_blockset.blockref[0];
742 bcount = HAMMER2_SET_COUNT;
753 * If failed, no recurse, but still verify its direct children.
754 * Beyond that is probably garbage.
756 for (i = 0; norecurse == false && i < bcount; ++i)
757 if (verify_blockref(fd, voldata, &bscan[i], failed, bstats)
760 return failed ? -1 : 0;
764 init_pfs_blockref(int fd, const hammer2_volume_data_t *voldata,
765 const hammer2_blockref_t *bref, struct blockref_list *blist)
767 hammer2_media_data_t media;
768 hammer2_inode_data_t ipdata;
769 hammer2_blockref_t *bscan;
773 if (read_media(fd, bref, &media, &bytes))
778 switch (bref->type) {
779 case HAMMER2_BREF_TYPE_INODE:
780 ipdata = media.ipdata;
781 if (ipdata.meta.pfs_type & HAMMER2_PFSTYPE_SUPROOT) {
782 bscan = &ipdata.u.blockset.blockref[0];
783 bcount = HAMMER2_SET_COUNT;
787 if (ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) {
788 struct blockref_msg *p;
789 p = calloc(1, sizeof(*p));
792 p->msg = strdup(ipdata.filename);
793 TAILQ_INSERT_TAIL(blist, p, entry);
795 assert(0); /* should only see SUPROOT or PFS */
798 case HAMMER2_BREF_TYPE_INDIRECT:
799 bscan = &media.npdata[0];
800 bcount = bytes / sizeof(hammer2_blockref_t);
802 case HAMMER2_BREF_TYPE_VOLUME:
803 bscan = &media.voldata.sroot_blockset.blockref[0];
804 bcount = HAMMER2_SET_COUNT;
812 for (i = 0; i < bcount; ++i)
813 if (init_pfs_blockref(fd, voldata, &bscan[i], blist) == -1)
819 cleanup_pfs_blockref(struct blockref_list *blist)
821 cleanup_blockref_msg(blist);
825 print_media(FILE *fp, int tab, const hammer2_blockref_t *bref,
826 hammer2_media_data_t *media, size_t media_bytes)
828 hammer2_blockref_t *bscan;
829 hammer2_inode_data_t *ipdata;
830 int i, bcount, namelen;
833 switch (bref->type) {
834 case HAMMER2_BREF_TYPE_INODE:
835 ipdata = &media->ipdata;
836 namelen = ipdata->meta.name_len;
837 if (namelen > HAMMER2_INODE_MAXNAME)
839 tfprintf(fp, tab, "filename \"%*.*s\"\n", namelen, namelen,
841 tfprintf(fp, tab, "version %d\n", ipdata->meta.version);
842 tfprintf(fp, tab, "pfs_subtype %d\n", ipdata->meta.pfs_subtype);
843 tfprintf(fp, tab, "uflags 0x%08x\n", ipdata->meta.uflags);
844 if (ipdata->meta.rmajor || ipdata->meta.rminor) {
845 tfprintf(fp, tab, "rmajor %d\n", ipdata->meta.rmajor);
846 tfprintf(fp, tab, "rminor %d\n", ipdata->meta.rminor);
848 tfprintf(fp, tab, "ctime %s\n",
849 hammer2_time64_to_str(ipdata->meta.ctime, &str));
850 tfprintf(fp, tab, "mtime %s\n",
851 hammer2_time64_to_str(ipdata->meta.mtime, &str));
852 tfprintf(fp, tab, "atime %s\n",
853 hammer2_time64_to_str(ipdata->meta.atime, &str));
854 tfprintf(fp, tab, "btime %s\n",
855 hammer2_time64_to_str(ipdata->meta.btime, &str));
856 tfprintf(fp, tab, "uid %s\n",
857 hammer2_uuid_to_str(&ipdata->meta.uid, &str));
858 tfprintf(fp, tab, "gid %s\n",
859 hammer2_uuid_to_str(&ipdata->meta.gid, &str));
860 tfprintf(fp, tab, "type %s\n",
861 hammer2_iptype_to_str(ipdata->meta.type));
862 tfprintf(fp, tab, "op_flags 0x%02x\n", ipdata->meta.op_flags);
863 tfprintf(fp, tab, "cap_flags 0x%04x\n", ipdata->meta.cap_flags);
864 tfprintf(fp, tab, "mode %-7o\n", ipdata->meta.mode);
865 tfprintf(fp, tab, "inum 0x%016jx\n", ipdata->meta.inum);
866 tfprintf(fp, tab, "size %ju ", (uintmax_t)ipdata->meta.size);
867 if (ipdata->meta.op_flags & HAMMER2_OPFLAG_DIRECTDATA &&
868 ipdata->meta.size <= HAMMER2_EMBEDDED_BYTES)
869 printf("(embedded data)\n");
872 tfprintf(fp, tab, "nlinks %ju\n",
873 (uintmax_t)ipdata->meta.nlinks);
874 tfprintf(fp, tab, "iparent 0x%016jx\n",
875 (uintmax_t)ipdata->meta.iparent);
876 tfprintf(fp, tab, "name_key 0x%016jx\n",
877 (uintmax_t)ipdata->meta.name_key);
878 tfprintf(fp, tab, "name_len %u\n", ipdata->meta.name_len);
879 tfprintf(fp, tab, "ncopies %u\n", ipdata->meta.ncopies);
880 tfprintf(fp, tab, "comp_algo %u\n", ipdata->meta.comp_algo);
881 tfprintf(fp, tab, "target_type %u\n", ipdata->meta.target_type);
882 tfprintf(fp, tab, "check_algo %u\n", ipdata->meta.check_algo);
883 if ((ipdata->meta.op_flags & HAMMER2_OPFLAG_PFSROOT) ||
884 ipdata->meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) {
885 tfprintf(fp, tab, "pfs_nmasters %u\n",
886 ipdata->meta.pfs_nmasters);
887 tfprintf(fp, tab, "pfs_type %u (%s)\n",
888 ipdata->meta.pfs_type,
889 hammer2_pfstype_to_str(ipdata->meta.pfs_type));
890 tfprintf(fp, tab, "pfs_inum 0x%016jx\n",
891 (uintmax_t)ipdata->meta.pfs_inum);
892 tfprintf(fp, tab, "pfs_clid %s\n",
893 hammer2_uuid_to_str(&ipdata->meta.pfs_clid, &str));
894 tfprintf(fp, tab, "pfs_fsid %s\n",
895 hammer2_uuid_to_str(&ipdata->meta.pfs_fsid, &str));
896 tfprintf(fp, tab, "pfs_lsnap_tid 0x%016jx\n",
897 (uintmax_t)ipdata->meta.pfs_lsnap_tid);
899 tfprintf(fp, tab, "data_quota %ju\n",
900 (uintmax_t)ipdata->meta.data_quota);
901 tfprintf(fp, tab, "data_count %ju\n",
902 (uintmax_t)bref->embed.stats.data_count);
903 tfprintf(fp, tab, "inode_quota %ju\n",
904 (uintmax_t)ipdata->meta.inode_quota);
905 tfprintf(fp, tab, "inode_count %ju\n",
906 (uintmax_t)bref->embed.stats.inode_count);
908 case HAMMER2_BREF_TYPE_INDIRECT:
909 bcount = media_bytes / sizeof(hammer2_blockref_t);
910 for (i = 0; i < bcount; ++i) {
911 bscan = &media->npdata[i];
912 tfprintf(fp, tab, "%3d %016jx %-12s %016jx/%-2d\n",
913 i, (uintmax_t)bscan->data_off,
914 hammer2_blockref_to_str(bscan->type),
915 (uintmax_t)bscan->key,
919 case HAMMER2_BREF_TYPE_DIRENT:
920 if (bref->embed.dirent.namlen <= sizeof(bref->check.buf)) {
921 tfprintf(fp, tab, "filename \"%*.*s\"\n",
922 bref->embed.dirent.namlen,
923 bref->embed.dirent.namlen,
926 tfprintf(fp, tab, "filename \"%*.*s\"\n",
927 bref->embed.dirent.namlen,
928 bref->embed.dirent.namlen,
931 tfprintf(fp, tab, "inum 0x%016jx\n",
932 (uintmax_t)bref->embed.dirent.inum);
933 tfprintf(fp, tab, "namlen %d\n",
934 (uintmax_t)bref->embed.dirent.namlen);
935 tfprintf(fp, tab, "type %s\n",
936 hammer2_iptype_to_str(bref->embed.dirent.type));
938 case HAMMER2_BREF_TYPE_FREEMAP_NODE:
939 bcount = media_bytes / sizeof(hammer2_blockref_t);
940 for (i = 0; i < bcount; ++i) {
941 bscan = &media->npdata[i];
942 tfprintf(fp, tab, "%3d %016jx %-12s %016jx/%-2d\n",
943 i, (uintmax_t)bscan->data_off,
944 hammer2_blockref_to_str(bscan->type),
945 (uintmax_t)bscan->key,
949 case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
950 for (i = 0; i < HAMMER2_FREEMAP_COUNT; ++i) {
951 hammer2_off_t data_off = bref->key +
952 i * HAMMER2_FREEMAP_LEVEL0_SIZE;
953 #if HAMMER2_BMAP_ELEMENTS != 8
954 #error "HAMMER2_BMAP_ELEMENTS != 8"
956 tfprintf(fp, tab, "%016jx %04d.%04x (avail=%7d) "
957 "%016jx %016jx %016jx %016jx "
958 "%016jx %016jx %016jx %016jx\n",
959 data_off, i, media->bmdata[i].class,
960 media->bmdata[i].avail,
961 media->bmdata[i].bitmapq[0],
962 media->bmdata[i].bitmapq[1],
963 media->bmdata[i].bitmapq[2],
964 media->bmdata[i].bitmapq[3],
965 media->bmdata[i].bitmapq[4],
966 media->bmdata[i].bitmapq[5],
967 media->bmdata[i].bitmapq[6],
968 media->bmdata[i].bitmapq[7]);
979 hammer2_blockref_to_str(uint8_t type)
982 case HAMMER2_BREF_TYPE_EMPTY:
984 case HAMMER2_BREF_TYPE_INODE:
986 case HAMMER2_BREF_TYPE_INDIRECT:
988 case HAMMER2_BREF_TYPE_DATA:
990 case HAMMER2_BREF_TYPE_DIRENT:
992 case HAMMER2_BREF_TYPE_FREEMAP_NODE:
993 return "freemap_node";
994 case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
995 return "freemap_leaf";
996 case HAMMER2_BREF_TYPE_FREEMAP:
998 case HAMMER2_BREF_TYPE_VOLUME:
1007 test_hammer2(const char *devpath)
1010 bool failed = false;
1013 fd = open(devpath, O_RDONLY);
1019 if (fstat(fd, &st) == -1) {
1024 if (!S_ISCHR(st.st_mode)) {
1025 fprintf(stderr, "%s is not a block device\n", devpath);
1030 best_zone = find_best_zone(fd);
1031 if (best_zone == -1)
1032 fprintf(stderr, "Failed to find best zone\n");
1034 printf("volume header\n");
1035 if (test_volume_header(fd) == -1) {
1041 printf("freemap\n");
1042 if (test_blockref(fd, HAMMER2_BREF_TYPE_FREEMAP) == -1) {
1049 if (test_blockref(fd, HAMMER2_BREF_TYPE_VOLUME) == -1) {
1055 if (test_pfs_blockref(fd, PFSName) == -1) {
1064 return failed ? -1 : 0;