2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@dragonflybsd.org>
6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific, prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include <openssl/sha.h>
40 #define GIG (1024LL*1024*1024)
42 static int show_all_volume_headers
= 0;
43 static int show_tab
= 2;
44 static int show_depth
= -1;
45 static hammer2_tid_t show_min_mirror_tid
= 0;
46 static hammer2_tid_t show_min_modify_tid
= 0;
48 static void shell_msghandler(dmsg_msg_t
*msg
, int unmanaged
);
49 static void shell_ttymsg(dmsg_iocom_t
*iocom
);
50 static void count_blocks(hammer2_bmap_data_t
*bmap
, int value
,
51 hammer2_off_t
*accum16
, hammer2_off_t
*accum64
);
53 /************************************************************************
55 ************************************************************************/
58 cmd_shell(const char *hostname
)
60 dmsg_master_service_info_t
*info
;
64 fd
= dmsg_connect(hostname
);
68 info
= malloc(sizeof(*info
));
69 bzero(info
, sizeof(*info
));
72 info
->usrmsg_callback
= shell_msghandler
;
73 info
->altmsg_callback
= shell_ttymsg
;
74 info
->label
= strdup("debug");
75 pthread_create(&thread
, NULL
, dmsg_master_service
, info
);
76 pthread_join(thread
, NULL
);
83 cmd_shell(const char *hostname
)
85 struct dmsg_iocom iocom
;
90 * Connect to the target
92 fd
= dmsg_connect(hostname
);
97 * Initialize the session and transmit an empty DMSG_DBG_SHELL
98 * to cause the remote end to generate a prompt.
100 dmsg_iocom_init(&iocom
, fd
, 0,
105 fcntl(0, F_SETFL
, O_NONBLOCK
);
106 printf("debug: connected\n");
108 msg
= dmsg_msg_alloc(&iocom
.state0
, 0, DMSG_DBG_SHELL
, NULL
, NULL
);
110 dmsg_iocom_core(&iocom
);
111 fprintf(stderr
, "debug: disconnected\n");
118 * Debug session front-end
120 * Callback from dmsg_iocom_core() when messages might be present
125 shell_msghandler(dmsg_msg_t
*msg
, int unmanaged
)
132 case DMSG_LNK_ERROR
| DMSGF_REPLY
:
134 * One-way non-transactional LNK_ERROR messages typically
135 * indicate a connection failure. Error code 0 is used by
136 * the debug shell to indicate no more results from last cmd.
138 if (msg
->any
.head
.error
) {
139 fprintf(stderr
, "Stream failure: %s\n",
142 write(1, "debug> ", 7);
145 case DMSG_LNK_ERROR
| DMSGF_DELETE
:
146 /* ignore termination of LNK_CONN */
151 * We send the commands, not accept them.
152 * (one-way message, not transactional)
155 dmsg_msg_reply(msg
, DMSG_ERR_NOSUPP
);
157 case DMSG_DBG_SHELL
| DMSGF_REPLY
:
159 * A reply from the remote is data we copy to stdout.
160 * (one-way message, not transactional)
163 msg
->aux_data
[msg
->aux_size
- 1] = 0;
164 write(1, msg
->aux_data
, strlen(msg
->aux_data
));
168 case DMSG_LNK_CONN
| DMSGF_CREATE
:
169 fprintf(stderr
, "Debug Shell received LNK_CONN\n");
170 nmsg
= dmsg_msg_alloc(&msg
->state
->iocom
->state0
, 0,
173 dmsg_msg_write(nmsg
);
174 dmsg_msg_reply(msg
, DMSG_ERR_NOSUPP
);
176 case DMSG_LNK_CONN
| DMSGF_DELETE
:
181 * Ignore any unknown messages, Terminate any unknown
182 * transactions with an error.
184 fprintf(stderr
, "Unknown message: %s\n", dmsg_msg_str(msg
));
186 if (msg
->any
.head
.cmd
& DMSGF_CREATE
)
187 dmsg_msg_reply(msg
, DMSG_ERR_NOSUPP
);
188 if (msg
->any
.head
.cmd
& DMSGF_DELETE
)
189 dmsg_msg_reply(msg
, DMSG_ERR_NOSUPP
);
196 * Debug session front-end
200 shell_ttymsg(dmsg_iocom_t
*iocom
)
202 dmsg_state_t
*pstate
;
208 if (fgets(buf
, sizeof(buf
), stdin
) != NULL
) {
210 pstate
= dmsg_findspan(strtok(buf
+ 1, " \t\n"));
211 cmd
= strtok(NULL
, "\n");
213 pstate
= &iocom
->state0
;
214 cmd
= strtok(buf
, "\n");
217 len
= strlen(cmd
) + 1;
218 msg
= dmsg_msg_alloc(pstate
, len
, DMSG_DBG_SHELL
,
220 bcopy(cmd
, msg
->aux_data
, len
);
223 fprintf(stderr
, "@msgid not found\n");
226 * This should cause the remote end to generate
227 * a debug> prompt (and thus shows that there is
230 msg
= dmsg_msg_alloc(pstate
, 0, DMSG_DBG_SHELL
,
234 } else if (feof(stdin
)) {
236 * Set EOF flag without setting any error code for normal
239 iocom
->flags
|= DMSG_IOCOMF_EOF
;
246 * Debug session back-end (on remote side)
248 static void shell_span(dmsg_msg_t
*msg
, char *cmdbuf
);
249 static void shell_ping(dmsg_msg_t
*msg
, char *cmdbuf
);
252 hammer2_shell_parse(dmsg_msg_t
*msg
, int unmanaged
)
254 dmsg_iocom_t
*iocom
= msg
->state
->iocom
;
260 * Filter on debug shell commands and ping responses only
262 cmd
= msg
->any
.head
.cmd
;
263 if ((cmd
& DMSGF_CMDSWMASK
) == (DMSG_LNK_PING
| DMSGF_REPLY
)) {
264 dmsg_printf(iocom
, "ping reply\n");
268 if ((cmd
& DMSGF_PROTOS
) != DMSG_PROTO_DBG
) {
270 dmsg_msg_reply(msg
, DMSG_ERR_NOSUPP
);
273 if ((cmd
& DMSGF_CMDSWMASK
) != DMSG_DBG_SHELL
) {
275 dmsg_msg_reply(msg
, DMSG_ERR_NOSUPP
);
280 * Debug shell command
282 cmdbuf
= msg
->aux_data
;
283 cmdp
= strsep(&cmdbuf
, " \t");
285 if (cmdp
== NULL
|| *cmdp
== 0) {
287 } else if (strcmp(cmdp
, "ping") == 0) {
288 shell_ping(msg
, cmdbuf
);
289 } else if (strcmp(cmdp
, "span") == 0) {
290 shell_span(msg
, cmdbuf
);
291 } else if (strcmp(cmdp
, "tree") == 0) {
292 dmsg_shell_tree(iocom
, cmdbuf
); /* dump spanning tree */
293 } else if (strcmp(cmdp
, "help") == 0 || strcmp(cmdp
, "?") == 0) {
294 dmsg_printf(iocom
, "help Command help\n");
295 dmsg_printf(iocom
, "span <host> Span to target host\n");
296 dmsg_printf(iocom
, "tree Dump spanning tree\n");
297 dmsg_printf(iocom
, "@span <cmd> Issue via circuit\n");
299 dmsg_printf(iocom
, "Unrecognized command: %s\n", cmdp
);
301 dmsg_printf(iocom
, "debug> ");
305 shell_ping(dmsg_msg_t
*msg
, char *cmdbuf __unused
)
307 dmsg_iocom_t
*iocom
= msg
->state
->iocom
;
310 dmsg_printf(iocom
, "sending ping\n");
311 m2
= dmsg_msg_alloc(msg
->state
, 0, DMSG_LNK_PING
, NULL
, NULL
);
316 shell_span(dmsg_msg_t
*msg
, char *cmdbuf
)
318 dmsg_iocom_t
*iocom
= msg
->state
->iocom
;
319 dmsg_master_service_info_t
*info
;
320 const char *hostname
= strsep(&cmdbuf
, " \t");
325 * Connect to the target
327 if (hostname
== NULL
) {
330 fd
= dmsg_connect(hostname
);
334 * Start master service
337 dmsg_printf(iocom
, "Connection to %s failed\n", hostname
);
339 dmsg_printf(iocom
, "Connected to %s\n", hostname
);
341 info
= malloc(sizeof(*info
));
342 bzero(info
, sizeof(*info
));
345 info
->usrmsg_callback
= hammer2_shell_parse
;
346 info
->label
= strdup("client");
348 pthread_create(&thread
, NULL
, dmsg_master_service
, info
);
349 /*pthread_join(thread, &res);*/
353 /************************************************************************
355 ************************************************************************
357 * Connect to the target manually (not via the cluster list embedded in
358 * a hammer2 filesystem) and initiate the SPAN protocol.
361 cmd_debugspan(const char *hostname
)
368 * Connect to the target
370 fd
= dmsg_connect(hostname
);
374 printf("debugspan: connected to %s, starting CONN/SPAN\n", hostname
);
375 pthread_create(&thread
, NULL
,
376 dmsg_master_service
, (void *)(intptr_t)fd
);
377 pthread_join(thread
, &res
);
381 /************************************************************************
383 ************************************************************************/
385 static void show_volhdr(hammer2_volume_data_t
*voldata
, int bi
);
386 static void show_bref(hammer2_volume_data_t
*voldata
, int tab
,
387 int bi
, hammer2_blockref_t
*bref
, int norecurse
);
388 static void tabprintf(int tab
, const char *ctl
, ...);
390 static hammer2_off_t TotalAccum16
[4]; /* includes TotalAccum64 */
391 static hammer2_off_t TotalAccum64
[4];
392 static hammer2_off_t TotalUnavail
;
393 static hammer2_off_t TotalFreemap
;
397 get_next_volume(hammer2_volume_data_t
*voldata
, hammer2_off_t volu_loff
)
399 hammer2_off_t ret
= -1;
402 for (i
= 0; i
< HAMMER2_MAX_VOLUMES
; ++i
) {
403 hammer2_off_t tmp
= voldata
->volu_loff
[i
];
404 if (tmp
> volu_loff
) {
413 cmd_show(const char *devpath
, int which
)
415 hammer2_blockref_t broot
;
416 hammer2_blockref_t best
;
417 hammer2_media_data_t media
;
418 hammer2_media_data_t best_media
;
419 hammer2_off_t off
, volu_loff
, next_volu_loff
= 0;
425 memset(TotalAccum16
, 0, sizeof(TotalAccum16
));
426 memset(TotalAccum64
, 0, sizeof(TotalAccum64
));
427 TotalUnavail
= TotalFreemap
= 0;
429 env
= getenv("HAMMER2_SHOW_ALL_VOLUME_HEADERS");
431 show_all_volume_headers
= (int)strtol(env
, NULL
, 0);
433 show_all_volume_headers
= 0;
435 env
= getenv("HAMMER2_SHOW_TAB");
437 show_tab
= (int)strtol(env
, NULL
, 0);
438 if (errno
|| show_tab
< 0 || show_tab
> 8)
441 env
= getenv("HAMMER2_SHOW_DEPTH");
443 show_depth
= (int)strtol(env
, NULL
, 0);
444 if (errno
|| show_depth
< 0)
447 env
= getenv("HAMMER2_SHOW_MIN_MIRROR_TID");
449 show_min_mirror_tid
= (hammer2_tid_t
)strtoull(env
, NULL
, 16);
451 show_min_mirror_tid
= 0;
453 env
= getenv("HAMMER2_SHOW_MIN_MODIFY_TID");
455 show_min_modify_tid
= (hammer2_tid_t
)strtoull(env
, NULL
, 16);
457 show_min_modify_tid
= 0;
460 hammer2_init_volumes(devpath
, 1);
461 int all_volume_headers
= VerboseOpt
>= 3 || show_all_volume_headers
;
463 volu_loff
= next_volu_loff
;
465 printf("%s\n", hammer2_get_volume_path(volu_loff
));
467 * Show the tree using the best volume header.
468 * -vvv will show the tree for all four volume headers.
471 bzero(&best
, sizeof(best
));
472 bzero(&best_media
, sizeof(best_media
));
473 for (i
= 0; i
< HAMMER2_NUM_VOLHDRS
; ++i
) {
474 bzero(&broot
, sizeof(broot
));
475 broot
.data_off
= (i
* HAMMER2_ZONE_BYTES64
) | HAMMER2_PBUFRADIX
;
476 off
= broot
.data_off
& ~HAMMER2_OFF_MASK_RADIX
;
477 fd
= hammer2_get_volume_fd(volu_loff
);
478 lseek(fd
, off
, SEEK_SET
);
479 if (read(fd
, &media
, HAMMER2_PBUFSIZE
) ==
480 (ssize_t
)HAMMER2_PBUFSIZE
) {
481 broot
.mirror_tid
= media
.voldata
.mirror_tid
;
482 if (best_i
< 0 || best
.mirror_tid
< broot
.mirror_tid
) {
487 printf("Volume header %d: mirror_tid=%016jx\n",
488 i
, (intmax_t)broot
.mirror_tid
);
490 if (all_volume_headers
) {
493 broot
.type
= HAMMER2_BREF_TYPE_VOLUME
;
494 show_bref(&media
.voldata
, 0, i
, &broot
,
498 broot
.type
= HAMMER2_BREF_TYPE_FREEMAP
;
499 show_bref(&media
.voldata
, 0, i
, &broot
,
503 show_volhdr(&media
.voldata
, i
);
505 next_volu_loff
= get_next_volume(&media
.voldata
, volu_loff
);
508 if (i
!= HAMMER2_NUM_VOLHDRS
- 1)
513 if (next_volu_loff
!= (hammer2_off_t
)-1) {
514 printf("---------------------------------------------\n");
518 if (!all_volume_headers
) {
521 best
.type
= HAMMER2_BREF_TYPE_VOLUME
;
522 show_bref(&best_media
.voldata
, 0, best_i
, &best
, 0);
525 best
.type
= HAMMER2_BREF_TYPE_FREEMAP
;
526 show_bref(&best_media
.voldata
, 0, best_i
, &best
, 0);
529 show_volhdr(&best_media
.voldata
, best_i
);
530 next_volu_loff
= get_next_volume(&best_media
.voldata
, volu_loff
);
531 if (next_volu_loff
!= (hammer2_off_t
)-1) {
532 printf("---------------------------------------------\n");
539 if (which
== 1 && VerboseOpt
< 3) {
540 printf("Total unallocated storage: %6.3fGiB (%6.3fGiB in 64KB chunks)\n",
541 (double)TotalAccum16
[0] / GIG
,
542 (double)TotalAccum64
[0] / GIG
);
543 printf("Total possibly free storage: %6.3fGiB (%6.3fGiB in 64KB chunks)\n",
544 (double)TotalAccum16
[2] / GIG
,
545 (double)TotalAccum64
[2] / GIG
);
546 printf("Total allocated storage: %6.3fGiB (%6.3fGiB in 64KB chunks)\n",
547 (double)TotalAccum16
[3] / GIG
,
548 (double)TotalAccum64
[3] / GIG
);
549 printf("Total unavailable storage: %6.3fGiB\n",
550 (double)TotalUnavail
/ GIG
);
551 printf("Total freemap storage: %6.3fGiB\n",
552 (double)TotalFreemap
/ GIG
);
554 hammer2_cleanup_volumes();
560 show_volhdr(hammer2_volume_data_t
*voldata
, int bi
)
569 printf("\nVolume header %d {\n", bi
);
570 printf(" magic 0x%016jx\n", (intmax_t)voldata
->magic
);
571 printf(" boot_beg 0x%016jx\n", (intmax_t)voldata
->boot_beg
);
572 printf(" boot_end 0x%016jx (%6.2fMB)\n",
573 (intmax_t)voldata
->boot_end
,
574 (double)(voldata
->boot_end
- voldata
->boot_beg
) /
576 printf(" aux_beg 0x%016jx\n", (intmax_t)voldata
->aux_beg
);
577 printf(" aux_end 0x%016jx (%6.2fMB)\n",
578 (intmax_t)voldata
->aux_end
,
579 (double)(voldata
->aux_end
- voldata
->aux_beg
) /
581 printf(" volu_size 0x%016jx (%6.2fGiB)\n",
582 (intmax_t)voldata
->volu_size
,
583 (double)voldata
->volu_size
/ GIG
);
584 printf(" version %d\n", voldata
->version
);
585 printf(" flags 0x%08x\n", voldata
->flags
);
586 printf(" copyid %d\n", voldata
->copyid
);
587 printf(" freemap_vers %d\n", voldata
->freemap_version
);
588 printf(" peer_type %d\n", voldata
->peer_type
);
589 printf(" volu_id %d\n", voldata
->volu_id
);
590 printf(" nvolumes %d\n", voldata
->nvolumes
);
593 uuid
= voldata
->fsid
;
594 hammer2_uuid_to_str(&uuid
, &str
);
595 printf(" fsid %s\n", str
);
600 uuid
= voldata
->fstype
;
601 hammer2_uuid_to_str(&uuid
, &str
);
602 printf(" fstype %s\n", str
);
603 uuid_addr_lookup(&voldata
->fstype
, &name
, &status
);
606 printf(" (%s)\n", name
);
610 printf(" allocator_size 0x%016jx (%6.2fGiB)\n",
611 voldata
->allocator_size
,
612 (double)voldata
->allocator_size
/ GIG
);
613 printf(" allocator_free 0x%016jx (%6.2fGiB)\n",
614 voldata
->allocator_free
,
615 (double)voldata
->allocator_free
/ GIG
);
616 printf(" allocator_beg 0x%016jx (%6.2fGiB)\n",
617 voldata
->allocator_beg
,
618 (double)voldata
->allocator_beg
/ GIG
);
620 printf(" mirror_tid 0x%016jx\n", voldata
->mirror_tid
);
621 printf(" reserved0080 0x%016jx\n", voldata
->reserved0080
);
622 printf(" reserved0088 0x%016jx\n", voldata
->reserved0088
);
623 printf(" freemap_tid 0x%016jx\n", voldata
->freemap_tid
);
624 printf(" bulkfree_tid 0x%016jx\n", voldata
->bulkfree_tid
);
625 for (i
= 0; i
< nitems(voldata
->reserved00A0
); ++i
) {
626 printf(" reserved00A0/%u 0x%016jx\n",
627 i
, voldata
->reserved00A0
[0]);
629 printf(" total_size 0x%016jx\n", voldata
->total_size
);
631 printf(" copyexists ");
632 for (i
= 0; i
< nitems(voldata
->copyexists
); ++i
)
633 printf(" 0x%02x", voldata
->copyexists
[i
]);
637 * NOTE: Index numbers and ICRC_SECTn definitions are not matched,
638 * the ICRC for sector 0 actually uses the last index, for
641 * NOTE: The whole voldata CRC does not have to match critically
642 * as certain sub-areas of the volume header have their own
646 for (i
= 0; i
< nitems(voldata
->icrc_sects
); ++i
) {
647 printf(" icrc_sects[%u] ", i
);
649 case HAMMER2_VOL_ICRC_SECT0
:
650 printf("0x%08x/0x%08x",
651 hammer2_icrc32((char *)voldata
+
652 HAMMER2_VOLUME_ICRC0_OFF
,
653 HAMMER2_VOLUME_ICRC0_SIZE
),
654 voldata
->icrc_sects
[HAMMER2_VOL_ICRC_SECT0
]);
655 if (hammer2_icrc32((char *)voldata
+
656 HAMMER2_VOLUME_ICRC0_OFF
,
657 HAMMER2_VOLUME_ICRC0_SIZE
) ==
658 voldata
->icrc_sects
[HAMMER2_VOL_ICRC_SECT0
]) {
664 case HAMMER2_VOL_ICRC_SECT1
:
665 printf("0x%08x/0x%08x",
666 hammer2_icrc32((char *)voldata
+
667 HAMMER2_VOLUME_ICRC1_OFF
,
668 HAMMER2_VOLUME_ICRC1_SIZE
),
669 voldata
->icrc_sects
[HAMMER2_VOL_ICRC_SECT1
]);
670 if (hammer2_icrc32((char *)voldata
+
671 HAMMER2_VOLUME_ICRC1_OFF
,
672 HAMMER2_VOLUME_ICRC1_SIZE
) ==
673 voldata
->icrc_sects
[HAMMER2_VOL_ICRC_SECT1
]) {
681 printf("0x%08x (reserved)", voldata
->icrc_sects
[i
]);
686 printf(" icrc_volhdr 0x%08x/0x%08x",
687 hammer2_icrc32((char *)voldata
+ HAMMER2_VOLUME_ICRCVH_OFF
,
688 HAMMER2_VOLUME_ICRCVH_SIZE
),
689 voldata
->icrc_volheader
);
690 if (hammer2_icrc32((char *)voldata
+ HAMMER2_VOLUME_ICRCVH_OFF
,
691 HAMMER2_VOLUME_ICRCVH_SIZE
) ==
692 voldata
->icrc_volheader
) {
695 printf(" (FAILED - not a critical error)\n");
699 * The super-root and freemap blocksets (not recursed)
702 printf(" sroot_blockset {\n");
703 for (i
= 0; i
< HAMMER2_SET_COUNT
; ++i
) {
704 show_bref(voldata
, 16, i
,
705 &voldata
->sroot_blockset
.blockref
[i
], 2);
709 printf(" freemap_blockset {\n");
710 for (i
= 0; i
< HAMMER2_SET_COUNT
; ++i
) {
711 show_bref(voldata
, 16, i
,
712 &voldata
->freemap_blockset
.blockref
[i
], 2);
716 buf
= calloc(1, sizeof(voldata
->volu_loff
));
717 if (bcmp(buf
, voldata
->volu_loff
, sizeof(voldata
->volu_loff
))) {
719 for (i
= 0; i
< HAMMER2_MAX_VOLUMES
; ++i
) {
720 hammer2_off_t loff
= voldata
->volu_loff
[i
];
721 if (loff
!= (hammer2_off_t
)-1)
722 printf(" volu_loff[%d] 0x%016jx\n", i
, loff
);
731 show_bref(hammer2_volume_data_t
*voldata
, int tab
, int bi
,
732 hammer2_blockref_t
*bref
, int norecurse
)
734 hammer2_media_data_t media
;
735 hammer2_blockref_t
*bscan
;
737 int i
, bcount
, namelen
, failed
, obrace
, fd
;
740 const char *type_str
;
742 char check_str
[32], comp_str
[32];
743 uint8_t check_algo
, comp_algo
;
746 static int init_tab
= -1;
751 uint8_t digest
[SHA256_DIGEST_LENGTH
];
752 uint64_t digest64
[SHA256_DIGEST_LENGTH
/8];
755 /* omit if smaller than mininum mirror_tid threshold */
756 if (bref
->mirror_tid
< show_min_mirror_tid
)
758 /* omit if smaller than mininum modify_tid threshold */
759 if (bref
->modify_tid
< show_min_modify_tid
) {
760 if (bref
->modify_tid
)
762 else if (bref
->type
== HAMMER2_BREF_TYPE_INODE
&& !bref
->leaf_count
)
769 bytes
= (bref
->data_off
& HAMMER2_OFF_MASK_RADIX
);
771 bytes
= (size_t)1 << bytes
;
773 hammer2_off_t io_off
;
774 hammer2_off_t io_base
;
778 io_off
= bref
->data_off
& ~HAMMER2_OFF_MASK_RADIX
;
779 io_base
= io_off
& ~(hammer2_off_t
)(HAMMER2_LBUFSIZE
- 1);
780 boff
= io_off
- io_base
;
782 io_bytes
= HAMMER2_LBUFSIZE
;
783 while (io_bytes
+ boff
< bytes
)
786 if (io_bytes
> sizeof(media
)) {
787 printf("(bad block size %zu)\n", bytes
);
790 if (bref
->type
!= HAMMER2_BREF_TYPE_DATA
|| VerboseOpt
>= 1) {
791 fd
= hammer2_get_volume_fd(io_off
);
792 lseek(fd
, io_base
- hammer2_get_volume_offset(io_base
),
794 if (read(fd
, &media
, io_bytes
) != (ssize_t
)io_bytes
) {
795 printf("(media read failed)\n");
799 bcopy((char *)&media
+ boff
, &media
, bytes
);
809 type_str
= hammer2_breftype_to_str(bref
->type
);
810 type_pad
= 8 - strlen(type_str
);
815 case HAMMER2_BREF_TYPE_INODE
:
817 if (!(media
.ipdata
.meta
.op_flags
& HAMMER2_OPFLAG_DIRECTDATA
)) {
818 bscan
= &media
.ipdata
.u
.blockset
.blockref
[0];
819 bcount
= HAMMER2_SET_COUNT
;
822 case HAMMER2_BREF_TYPE_INDIRECT
:
824 bscan
= &media
.npdata
[0];
825 bcount
= bytes
/ sizeof(hammer2_blockref_t
);
827 case HAMMER2_BREF_TYPE_VOLUME
:
828 bscan
= &media
.voldata
.sroot_blockset
.blockref
[0];
829 bcount
= HAMMER2_SET_COUNT
;
831 case HAMMER2_BREF_TYPE_FREEMAP
:
832 bscan
= &media
.voldata
.freemap_blockset
.blockref
[0];
833 bcount
= HAMMER2_SET_COUNT
;
835 case HAMMER2_BREF_TYPE_FREEMAP_NODE
:
837 bscan
= &media
.npdata
[0];
838 bcount
= bytes
/ sizeof(hammer2_blockref_t
);
844 "%s.%-3d %016jx %016jx/%-2d "
845 "vol=%d mir=%016jx mod=%016jx leafcnt=%d ",
846 type_str
, bi
, (intmax_t)bref
->data_off
,
847 (intmax_t)bref
->key
, (intmax_t)bref
->keybits
,
848 hammer2_get_volume_id(bref
->data_off
),
849 (intmax_t)bref
->mirror_tid
,
850 (intmax_t)bref
->modify_tid
,
853 tabprintf(tab
, "%s.%-3d%*.*s %016jx %016jx/%-2d ",
854 type_str
, bi
, type_pad
, type_pad
, "",
855 (intmax_t)bref
->data_off
,
856 (intmax_t)bref
->key
, (intmax_t)bref
->keybits
);
857 /*if (norecurse > 1)*/ {
859 tabprintf(tab
+ 13, "");
861 printf("vol=%d mir=%016jx mod=%016jx lfcnt=%d ",
862 hammer2_get_volume_id(bref
->data_off
),
863 (intmax_t)bref
->mirror_tid
, (intmax_t)bref
->modify_tid
,
865 if (/*norecurse > 1 && */ (bcount
|| bref
->flags
||
866 bref
->type
== HAMMER2_BREF_TYPE_FREEMAP_NODE
||
867 bref
->type
== HAMMER2_BREF_TYPE_FREEMAP_LEAF
)) {
869 tabprintf(tab
+ 13, "");
874 printf("bcnt=%d ", bcount
);
876 printf("flags=%02x ", bref
->flags
);
877 if (bref
->type
== HAMMER2_BREF_TYPE_FREEMAP_NODE
||
878 bref
->type
== HAMMER2_BREF_TYPE_FREEMAP_LEAF
) {
879 printf("bigmask=%08x avail=%ju ",
880 bref
->check
.freemap
.bigmask
,
881 (uintmax_t)bref
->check
.freemap
.avail
);
885 * Check data integrity in verbose mode, otherwise we are just doing
886 * a quick meta-data scan. Meta-data integrity is always checked.
887 * (Also see the check above that ensures the media data is loaded,
888 * otherwise there's no data to check!).
890 * WARNING! bref->check state may be used for other things when
891 * bref has no data (bytes == 0).
894 (bref
->type
!= HAMMER2_BREF_TYPE_DATA
|| VerboseOpt
>= 1)) {
895 if (!(QuietOpt
> 0)) {
896 /*if (norecurse > 1)*/ {
898 tabprintf(tab
+ 13, "");
902 check_algo
= HAMMER2_DEC_CHECK(bref
->methods
);
903 strlcpy(check_str
, hammer2_checkmode_to_str(check_algo
),
905 comp_algo
= HAMMER2_DEC_COMP(bref
->methods
);
906 strlcpy(comp_str
, hammer2_compmode_to_str(comp_algo
),
910 case HAMMER2_CHECK_NONE
:
911 printf("meth=%s|%s ", check_str
, comp_str
);
913 case HAMMER2_CHECK_DISABLED
:
914 printf("meth=%s|%s ", check_str
, comp_str
);
916 case HAMMER2_CHECK_ISCSI32
:
917 cv
= hammer2_icrc32(&media
, bytes
);
918 if (bref
->check
.iscsi32
.value
!= cv
) {
919 printf("(icrc %s|%s %08x/%08x failed) ",
921 bref
->check
.iscsi32
.value
,
925 printf("meth=%s|%s iscsi32=%08x ",
926 check_str
, comp_str
, cv
);
929 case HAMMER2_CHECK_XXHASH64
:
930 cv64
= XXH64(&media
, bytes
, XXH_HAMMER2_SEED
);
931 if (bref
->check
.xxhash64
.value
!= cv64
) {
932 printf("(xxhash64 %s|%s %016jx/%016jx failed) ",
934 bref
->check
.xxhash64
.value
,
938 printf("meth=%s|%s xxh=%016jx ",
939 check_str
, comp_str
, cv64
);
942 case HAMMER2_CHECK_SHA192
:
943 SHA256_Init(&hash_ctx
);
944 SHA256_Update(&hash_ctx
, &media
, bytes
);
945 SHA256_Final(u
.digest
, &hash_ctx
);
946 u
.digest64
[2] ^= u
.digest64
[3];
947 if (memcmp(u
.digest
, bref
->check
.sha192
.data
,
948 sizeof(bref
->check
.sha192
.data
))) {
949 printf("(sha192 %s:%s failed) ",
950 check_str
, comp_str
);
953 printf("meth=%s|%s ", check_str
, comp_str
);
956 case HAMMER2_CHECK_FREEMAP
:
957 cv
= hammer2_icrc32(&media
, bytes
);
958 if (bref
->check
.freemap
.icrc32
!= cv
) {
959 printf("(fcrc %s|%s %08x/%08x failed) ",
961 bref
->check
.freemap
.icrc32
,
965 printf("meth=%s|%s fcrc=%08x ",
966 check_str
, comp_str
, cv
);
981 case HAMMER2_BREF_TYPE_EMPTY
:
986 case HAMMER2_BREF_TYPE_DIRENT
:
988 if (bref
->embed
.dirent
.namlen
<= sizeof(bref
->check
.buf
)) {
989 tabprintf(tab
, "filename \"%*.*s\"\n",
990 bref
->embed
.dirent
.namlen
,
991 bref
->embed
.dirent
.namlen
,
994 tabprintf(tab
, "filename \"%*.*s\"\n",
995 bref
->embed
.dirent
.namlen
,
996 bref
->embed
.dirent
.namlen
,
999 tabprintf(tab
, "inum 0x%016jx\n",
1000 (uintmax_t)bref
->embed
.dirent
.inum
);
1001 tabprintf(tab
, "nlen %d\n", bref
->embed
.dirent
.namlen
);
1002 tabprintf(tab
, "type %s\n",
1003 hammer2_iptype_to_str(bref
->embed
.dirent
.type
));
1005 case HAMMER2_BREF_TYPE_INODE
:
1007 namelen
= media
.ipdata
.meta
.name_len
;
1008 if (namelen
> HAMMER2_INODE_MAXNAME
)
1010 tabprintf(tab
, "filename \"%*.*s\"\n",
1011 namelen
, namelen
, media
.ipdata
.filename
);
1012 tabprintf(tab
, "version %d\n", media
.ipdata
.meta
.version
);
1013 if ((media
.ipdata
.meta
.op_flags
& HAMMER2_OPFLAG_PFSROOT
) ||
1014 media
.ipdata
.meta
.pfs_type
== HAMMER2_PFSTYPE_SUPROOT
) {
1015 tabprintf(tab
, "pfs_st %d (%s)\n",
1016 media
.ipdata
.meta
.pfs_subtype
,
1017 hammer2_pfssubtype_to_str(media
.ipdata
.meta
.pfs_subtype
));
1019 tabprintf(tab
, "uflags 0x%08x\n",
1020 media
.ipdata
.meta
.uflags
);
1021 if (media
.ipdata
.meta
.rmajor
|| media
.ipdata
.meta
.rminor
) {
1022 tabprintf(tab
, "rmajor %d\n",
1023 media
.ipdata
.meta
.rmajor
);
1024 tabprintf(tab
, "rminor %d\n",
1025 media
.ipdata
.meta
.rminor
);
1027 tabprintf(tab
, "ctime %s\n",
1028 hammer2_time64_to_str(media
.ipdata
.meta
.ctime
, &str
));
1029 tabprintf(tab
, "mtime %s\n",
1030 hammer2_time64_to_str(media
.ipdata
.meta
.mtime
, &str
));
1031 tabprintf(tab
, "atime %s\n",
1032 hammer2_time64_to_str(media
.ipdata
.meta
.atime
, &str
));
1033 tabprintf(tab
, "btime %s\n",
1034 hammer2_time64_to_str(media
.ipdata
.meta
.btime
, &str
));
1035 uuid
= media
.ipdata
.meta
.uid
;
1036 tabprintf(tab
, "uid %s\n",
1037 hammer2_uuid_to_str(&uuid
, &str
));
1038 uuid
= media
.ipdata
.meta
.gid
;
1039 tabprintf(tab
, "gid %s\n",
1040 hammer2_uuid_to_str(&uuid
, &str
));
1041 tabprintf(tab
, "type %s\n",
1042 hammer2_iptype_to_str(media
.ipdata
.meta
.type
));
1043 tabprintf(tab
, "opflgs 0x%02x\n",
1044 media
.ipdata
.meta
.op_flags
);
1045 tabprintf(tab
, "capflgs 0x%04x\n",
1046 media
.ipdata
.meta
.cap_flags
);
1047 tabprintf(tab
, "mode %-7o\n",
1048 media
.ipdata
.meta
.mode
);
1049 tabprintf(tab
, "inum 0x%016jx\n",
1050 media
.ipdata
.meta
.inum
);
1051 tabprintf(tab
, "size %ju ",
1052 (uintmax_t)media
.ipdata
.meta
.size
);
1053 if (media
.ipdata
.meta
.op_flags
& HAMMER2_OPFLAG_DIRECTDATA
&&
1054 media
.ipdata
.meta
.size
<= HAMMER2_EMBEDDED_BYTES
)
1055 printf("(embedded data)\n");
1058 tabprintf(tab
, "nlinks %ju\n",
1059 (uintmax_t)media
.ipdata
.meta
.nlinks
);
1060 tabprintf(tab
, "iparent 0x%016jx\n",
1061 (uintmax_t)media
.ipdata
.meta
.iparent
);
1062 tabprintf(tab
, "name_key 0x%016jx\n",
1063 (uintmax_t)media
.ipdata
.meta
.name_key
);
1064 tabprintf(tab
, "name_len %u\n",
1065 media
.ipdata
.meta
.name_len
);
1066 tabprintf(tab
, "ncopies %u\n",
1067 media
.ipdata
.meta
.ncopies
);
1068 tabprintf(tab
, "compalg %s\n",
1069 hammer2_compmode_to_str(media
.ipdata
.meta
.comp_algo
));
1070 tabprintf(tab
, "target_t %u\n",
1071 media
.ipdata
.meta
.target_type
);
1072 tabprintf(tab
, "checkalg %s\n",
1073 hammer2_checkmode_to_str(media
.ipdata
.meta
.check_algo
));
1074 if ((media
.ipdata
.meta
.op_flags
& HAMMER2_OPFLAG_PFSROOT
) ||
1075 media
.ipdata
.meta
.pfs_type
== HAMMER2_PFSTYPE_SUPROOT
) {
1076 tabprintf(tab
, "pfs_nmas %u\n",
1077 media
.ipdata
.meta
.pfs_nmasters
);
1078 tabprintf(tab
, "pfs_type %u (%s)\n",
1079 media
.ipdata
.meta
.pfs_type
,
1080 hammer2_pfstype_to_str(media
.ipdata
.meta
.pfs_type
));
1081 tabprintf(tab
, "pfs_inum 0x%016jx\n",
1082 (uintmax_t)media
.ipdata
.meta
.pfs_inum
);
1083 uuid
= media
.ipdata
.meta
.pfs_clid
;
1084 tabprintf(tab
, "pfs_clid %s\n",
1085 hammer2_uuid_to_str(&uuid
, &str
));
1086 uuid
= media
.ipdata
.meta
.pfs_fsid
;
1087 tabprintf(tab
, "pfs_fsid %s\n",
1088 hammer2_uuid_to_str(&uuid
, &str
));
1089 tabprintf(tab
, "pfs_lsnap_tid 0x%016jx\n",
1090 (uintmax_t)media
.ipdata
.meta
.pfs_lsnap_tid
);
1092 tabprintf(tab
, "data_quota %ju\n",
1093 (uintmax_t)media
.ipdata
.meta
.data_quota
);
1094 tabprintf(tab
, "data_count %ju\n",
1095 (uintmax_t)bref
->embed
.stats
.data_count
);
1096 tabprintf(tab
, "inode_quota %ju\n",
1097 (uintmax_t)media
.ipdata
.meta
.inode_quota
);
1098 tabprintf(tab
, "inode_count %ju\n",
1099 (uintmax_t)bref
->embed
.stats
.inode_count
);
1101 case HAMMER2_BREF_TYPE_INDIRECT
:
1104 case HAMMER2_BREF_TYPE_DATA
:
1108 case HAMMER2_BREF_TYPE_VOLUME
:
1109 printf("mirror_tid=%016jx freemap_tid=%016jx ",
1110 media
.voldata
.mirror_tid
,
1111 media
.voldata
.freemap_tid
);
1114 case HAMMER2_BREF_TYPE_FREEMAP
:
1115 printf("mirror_tid=%016jx freemap_tid=%016jx ",
1116 media
.voldata
.mirror_tid
,
1117 media
.voldata
.freemap_tid
);
1120 case HAMMER2_BREF_TYPE_FREEMAP_LEAF
:
1122 tmp
= bref
->data_off
& ~HAMMER2_OFF_MASK_RADIX
;
1123 tmp
&= HAMMER2_SEGMASK
;
1124 tmp
/= HAMMER2_PBUFSIZE
;
1125 assert(tmp
>= HAMMER2_ZONE_FREEMAP_00
);
1126 assert(tmp
< HAMMER2_ZONE_FREEMAP_END
);
1127 tmp
-= HAMMER2_ZONE_FREEMAP_00
;
1128 tmp
/= HAMMER2_ZONE_FREEMAP_INC
;
1129 tabprintf(tab
, "rotation=%d\n", (int)tmp
);
1131 for (i
= 0; i
< HAMMER2_FREEMAP_COUNT
; ++i
) {
1132 hammer2_off_t data_off
= bref
->key
+
1133 i
* HAMMER2_FREEMAP_LEVEL0_SIZE
;
1134 #if HAMMER2_BMAP_ELEMENTS != 8
1135 #error "cmd_debug.c: HAMMER2_BMAP_ELEMENTS expected to be 8"
1137 tabprintf(tab
+ 4, "%016jx %04d.%04x linear=%06x avail=%06x "
1138 "%016jx %016jx %016jx %016jx "
1139 "%016jx %016jx %016jx %016jx\n",
1140 data_off
, i
, media
.bmdata
[i
].class,
1141 media
.bmdata
[i
].linear
,
1142 media
.bmdata
[i
].avail
,
1143 media
.bmdata
[i
].bitmapq
[0],
1144 media
.bmdata
[i
].bitmapq
[1],
1145 media
.bmdata
[i
].bitmapq
[2],
1146 media
.bmdata
[i
].bitmapq
[3],
1147 media
.bmdata
[i
].bitmapq
[4],
1148 media
.bmdata
[i
].bitmapq
[5],
1149 media
.bmdata
[i
].bitmapq
[6],
1150 media
.bmdata
[i
].bitmapq
[7]);
1152 tabprintf(tab
, "}\n");
1154 case HAMMER2_BREF_TYPE_FREEMAP_NODE
:
1156 tmp
= bref
->data_off
& ~HAMMER2_OFF_MASK_RADIX
;
1157 tmp
&= HAMMER2_SEGMASK
;
1158 tmp
/= HAMMER2_PBUFSIZE
;
1159 assert(tmp
>= HAMMER2_ZONE_FREEMAP_00
);
1160 assert(tmp
< HAMMER2_ZONE_FREEMAP_END
);
1161 tmp
-= HAMMER2_ZONE_FREEMAP_00
;
1162 tmp
/= HAMMER2_ZONE_FREEMAP_INC
;
1163 tabprintf(tab
, "rotation=%d\n", (int)tmp
);
1175 * Update statistics.
1177 switch(bref
->type
) {
1178 case HAMMER2_BREF_TYPE_FREEMAP_LEAF
:
1179 for (i
= 0; i
< HAMMER2_FREEMAP_COUNT
; ++i
) {
1180 hammer2_off_t data_off
= bref
->key
+
1181 i
* HAMMER2_FREEMAP_LEVEL0_SIZE
;
1182 if (data_off
>= voldata
->aux_end
&&
1183 data_off
< hammer2_get_total_size()) {
1185 for (j
= 0; j
< 4; ++j
)
1186 count_blocks(&media
.bmdata
[i
], j
,
1190 TotalUnavail
+= HAMMER2_FREEMAP_LEVEL0_SIZE
;
1192 TotalFreemap
+= HAMMER2_FREEMAP_LEVEL1_SIZE
;
1199 * Recurse if norecurse == 0. If the CRC failed, pass norecurse = 1.
1200 * That is, if an indirect or inode fails we still try to list its
1201 * direct children to help with debugging, but go no further than
1202 * that because they are probably garbage.
1204 if (show_depth
== -1 || ((tab
- init_tab
) / show_tab
) < show_depth
) {
1205 for (i
= 0; norecurse
== 0 && i
< bcount
; ++i
) {
1206 if (bscan
[i
].type
!= HAMMER2_BREF_TYPE_EMPTY
) {
1207 show_bref(voldata
, tab
, i
, &bscan
[i
],
1214 if (bref
->type
== HAMMER2_BREF_TYPE_INODE
)
1215 tabprintf(tab
, "} (%s.%d, \"%*.*s\")\n",
1216 type_str
, bi
, namelen
, namelen
,
1217 media
.ipdata
.filename
);
1219 tabprintf(tab
, "} (%s.%d)\n", type_str
, bi
);
1225 count_blocks(hammer2_bmap_data_t
*bmap
, int value
,
1226 hammer2_off_t
*accum16
, hammer2_off_t
*accum64
)
1229 hammer2_bitmap_t value16
, value64
;
1231 bits
= (int)sizeof(hammer2_bitmap_t
) * 8;
1235 assert(value16
< 4);
1236 value64
= (value16
<< 6) | (value16
<< 4) | (value16
<< 2) | value16
;
1237 assert(value64
< 256);
1239 for (i
= 0; i
< HAMMER2_BMAP_ELEMENTS
; ++i
) {
1240 hammer2_bitmap_t bm
= bmap
->bitmapq
[i
];
1241 hammer2_bitmap_t bm_save
= bm
;
1242 hammer2_bitmap_t mask
;
1244 mask
= 0x03; /* 2 bits per 16KB */
1245 for (j
= 0; j
< bits
; j
+= 2) {
1246 if ((bm
& mask
) == value16
)
1252 mask
= 0xFF; /* 8 bits per 64KB chunk */
1253 for (j
= 0; j
< bits
; j
+= 8) {
1254 if ((bm
& mask
) == value64
)
1262 cmd_hash(int ac
, const char **av
)
1266 for (i
= 0; i
< ac
; ++i
) {
1267 printf("%016jx %s\n",
1268 dirhash(av
[i
], strlen(av
[i
])),
1275 cmd_dhash(int ac
, const char **av
)
1277 char buf
[1024]; /* 1K extended directory record */
1281 for (i
= 0; i
< ac
; ++i
) {
1282 bzero(buf
, sizeof(buf
));
1283 snprintf(buf
, sizeof(buf
), "%s", av
[i
]);
1284 hash
= XXH64(buf
, sizeof(buf
), XXH_HAMMER2_SEED
);
1285 printf("%016jx %s\n", hash
, av
[i
]);
1291 cmd_dumpchain(const char *path
, u_int flags
)
1293 int dummy
= (int)flags
;
1297 fd
= open(path
, O_RDONLY
);
1299 if (ioctl(fd
, HAMMER2IOC_DEBUG_DUMP
, &dummy
) < 0) {
1300 fprintf(stderr
, "%s: %s\n", path
, strerror(errno
));
1305 fprintf(stderr
, "unable to open %s\n", path
);
1313 tabprintf(int tab
, const char *ctl
, ...)
1317 printf("%*.*s", tab
, tab
, "");