1 /*
2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved.
3 *
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>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
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
17 * distribution.
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.
21 *
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
33 * SUCH DAMAGE.
34 */
35
36 #include "hammer2.h"
37
38 #include <openssl/sha.h>
39
40 #define GIG (1024LL*1024*1024)
41
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;
47
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);
52
53 /************************************************************************
54 * SHELL *
55 ************************************************************************/
56
57 int
cmd_shell(const char * hostname)58 cmd_shell(const char *hostname)
59 {
60 dmsg_master_service_info_t *info;
61 pthread_t thread;
62 int fd;
63
64 fd = dmsg_connect(hostname);
65 if (fd < 0)
66 return 1;
67
68 info = malloc(sizeof(*info));
69 bzero(info, sizeof(*info));
70 info->fd = fd;
71 info->detachme = 0;
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);
77
78 return 0;
79 }
80
81 #if 0
82 int
83 cmd_shell(const char *hostname)
84 {
85 struct dmsg_iocom iocom;
86 dmsg_msg_t *msg;
87 int fd;
88
89 /*
90 * Connect to the target
91 */
92 fd = dmsg_connect(hostname);
93 if (fd < 0)
94 return 1;
95
96 /*
97 * Initialize the session and transmit an empty DMSG_DBG_SHELL
98 * to cause the remote end to generate a prompt.
99 */
100 dmsg_iocom_init(&iocom, fd, 0,
101 NULL,
102 shell_rcvmsg,
103 hammer2_shell_parse,
104 shell_ttymsg);
105 fcntl(0, F_SETFL, O_NONBLOCK);
106 printf("debug: connected\n");
107
108 msg = dmsg_msg_alloc(&iocom.state0, 0, DMSG_DBG_SHELL, NULL, NULL);
109 dmsg_msg_write(msg);
110 dmsg_iocom_core(&iocom);
111 fprintf(stderr, "debug: disconnected\n");
112 close(fd);
113 return 0;
114 }
115 #endif
116
117 /*
118 * Debug session front-end
119 *
120 * Callback from dmsg_iocom_core() when messages might be present
121 * on the socket.
122 */
123 static
124 void
shell_msghandler(dmsg_msg_t * msg,int unmanaged)125 shell_msghandler(dmsg_msg_t *msg, int unmanaged)
126 {
127 dmsg_msg_t *nmsg;
128
129 switch(msg->tcmd) {
130 #if 0
131 case DMSG_LNK_ERROR:
132 case DMSG_LNK_ERROR | DMSGF_REPLY:
133 /*
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.
137 */
138 if (msg->any.head.error) {
139 fprintf(stderr, "Stream failure: %s\n",
140 dmsg_msg_str(msg));
141 } else {
142 write(1, "debug> ", 7);
143 }
144 break;
145 case DMSG_LNK_ERROR | DMSGF_DELETE:
146 /* ignore termination of LNK_CONN */
147 break;
148 #endif
149 case DMSG_DBG_SHELL:
150 /*
151 * We send the commands, not accept them.
152 * (one-way message, not transactional)
153 */
154 if (unmanaged)
155 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP);
156 break;
157 case DMSG_DBG_SHELL | DMSGF_REPLY:
158 /*
159 * A reply from the remote is data we copy to stdout.
160 * (one-way message, not transactional)
161 */
162 if (msg->aux_size) {
163 msg->aux_data[msg->aux_size - 1] = 0;
164 write(1, msg->aux_data, strlen(msg->aux_data));
165 }
166 break;
167 #if 1
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,
171 DMSG_DBG_SHELL,
172 NULL, NULL);
173 dmsg_msg_write(nmsg);
174 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP);
175 break;
176 case DMSG_LNK_CONN | DMSGF_DELETE:
177 break;
178 #endif
179 default:
180 /*
181 * Ignore any unknown messages, Terminate any unknown
182 * transactions with an error.
183 */
184 fprintf(stderr, "Unknown message: %s\n", dmsg_msg_str(msg));
185 if (unmanaged) {
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);
190 }
191 break;
192 }
193 }
194
195 /*
196 * Debug session front-end
197 */
198 static
199 void
shell_ttymsg(dmsg_iocom_t * iocom)200 shell_ttymsg(dmsg_iocom_t *iocom)
201 {
202 dmsg_state_t *pstate;
203 dmsg_msg_t *msg;
204 char buf[256];
205 char *cmd;
206 size_t len;
207
208 if (fgets(buf, sizeof(buf), stdin) != NULL) {
209 if (buf[0] == '@') {
210 pstate = dmsg_findspan(strtok(buf + 1, " \t\n"));
211 cmd = strtok(NULL, "\n");
212 } else {
213 pstate = &iocom->state0;
214 cmd = strtok(buf, "\n");
215 }
216 if (cmd && pstate) {
217 len = strlen(cmd) + 1;
218 msg = dmsg_msg_alloc(pstate, len, DMSG_DBG_SHELL,
219 NULL, NULL);
220 bcopy(cmd, msg->aux_data, len);
221 dmsg_msg_write(msg);
222 } else if (cmd) {
223 fprintf(stderr, "@msgid not found\n");
224 } else {
225 /*
226 * This should cause the remote end to generate
227 * a debug> prompt (and thus shows that there is
228 * connectivity).
229 */
230 msg = dmsg_msg_alloc(pstate, 0, DMSG_DBG_SHELL,
231 NULL, NULL);
232 dmsg_msg_write(msg);
233 }
234 } else if (feof(stdin)) {
235 /*
236 * Set EOF flag without setting any error code for normal
237 * EOF.
238 */
239 iocom->flags |= DMSG_IOCOMF_EOF;
240 } else {
241 clearerr(stdin);
242 }
243 }
244
245 /*
246 * Debug session back-end (on remote side)
247 */
248 static void shell_span(dmsg_msg_t *msg, char *cmdbuf);
249 static void shell_ping(dmsg_msg_t *msg, char *cmdbuf);
250
251 void
hammer2_shell_parse(dmsg_msg_t * msg,int unmanaged)252 hammer2_shell_parse(dmsg_msg_t *msg, int unmanaged)
253 {
254 dmsg_iocom_t *iocom = msg->state->iocom;
255 char *cmdbuf;
256 char *cmdp;
257 uint32_t cmd;
258
259 /*
260 * Filter on debug shell commands and ping responses only
261 */
262 cmd = msg->any.head.cmd;
263 if ((cmd & DMSGF_CMDSWMASK) == (DMSG_LNK_PING | DMSGF_REPLY)) {
264 dmsg_printf(iocom, "ping reply\n");
265 return;
266 }
267
268 if ((cmd & DMSGF_PROTOS) != DMSG_PROTO_DBG) {
269 if (unmanaged)
270 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP);
271 return;
272 }
273 if ((cmd & DMSGF_CMDSWMASK) != DMSG_DBG_SHELL) {
274 if (unmanaged)
275 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP);
276 return;
277 }
278
279 /*
280 * Debug shell command
281 */
282 cmdbuf = msg->aux_data;
283 cmdp = strsep(&cmdbuf, " \t");
284
285 if (cmdp == NULL || *cmdp == 0) {
286 ;
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");
298 } else {
299 dmsg_printf(iocom, "Unrecognized command: %s\n", cmdp);
300 }
301 dmsg_printf(iocom, "debug> ");
302 }
303
304 static void
shell_ping(dmsg_msg_t * msg,char * cmdbuf __unused)305 shell_ping(dmsg_msg_t *msg, char *cmdbuf __unused)
306 {
307 dmsg_iocom_t *iocom = msg->state->iocom;
308 dmsg_msg_t *m2;
309
310 dmsg_printf(iocom, "sending ping\n");
311 m2 = dmsg_msg_alloc(msg->state, 0, DMSG_LNK_PING, NULL, NULL);
312 dmsg_msg_write(m2);
313 }
314
315 static void
shell_span(dmsg_msg_t * msg,char * cmdbuf)316 shell_span(dmsg_msg_t *msg, char *cmdbuf)
317 {
318 dmsg_iocom_t *iocom = msg->state->iocom;
319 dmsg_master_service_info_t *info;
320 const char *hostname = strsep(&cmdbuf, " \t");
321 pthread_t thread;
322 int fd;
323
324 /*
325 * Connect to the target
326 */
327 if (hostname == NULL) {
328 fd = -1;
329 } else {
330 fd = dmsg_connect(hostname);
331 }
332
333 /*
334 * Start master service
335 */
336 if (fd < 0) {
337 dmsg_printf(iocom, "Connection to %s failed\n", hostname);
338 } else {
339 dmsg_printf(iocom, "Connected to %s\n", hostname);
340
341 info = malloc(sizeof(*info));
342 bzero(info, sizeof(*info));
343 info->fd = fd;
344 info->detachme = 1;
345 info->usrmsg_callback = hammer2_shell_parse;
346 info->label = strdup("client");
347
348 pthread_create(&thread, NULL, dmsg_master_service, info);
349 /*pthread_join(thread, &res);*/
350 }
351 }
352
353 /************************************************************************
354 * DEBUGSPAN *
355 ************************************************************************
356 *
357 * Connect to the target manually (not via the cluster list embedded in
358 * a hammer2 filesystem) and initiate the SPAN protocol.
359 */
360 int
cmd_debugspan(const char * hostname)361 cmd_debugspan(const char *hostname)
362 {
363 pthread_t thread;
364 int fd;
365 void *res;
366
367 /*
368 * Connect to the target
369 */
370 fd = dmsg_connect(hostname);
371 if (fd < 0)
372 return 1;
373
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);
378 return(0);
379 }
380
381 /************************************************************************
382 * SHOW *
383 ************************************************************************/
384
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, ...);
389
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;
394
395 static
396 hammer2_off_t
get_next_volume(hammer2_volume_data_t * voldata,hammer2_off_t volu_loff)397 get_next_volume(hammer2_volume_data_t *voldata, hammer2_off_t volu_loff)
398 {
399 hammer2_off_t ret = -1;
400 int i;
401
402 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
403 hammer2_off_t tmp = voldata->volu_loff[i];
404 if (tmp > volu_loff) {
405 ret = tmp;
406 break;
407 }
408 }
409 return ret;
410 }
411
412 int
cmd_show(const char * devpath,int which)413 cmd_show(const char *devpath, int which)
414 {
415 hammer2_blockref_t broot;
416 hammer2_media_data_t media;
417 hammer2_off_t off, volu_loff, next_volu_loff = 0;
418 hammer2_tid_t best_mirror_tid = 0;
419 int bests[HAMMER2_MAX_VOLUMES];
420 int fd;
421 int i, j;
422 char *env;
423
424 memset(bests, 0xff, sizeof(bests));
425 memset(TotalAccum16, 0, sizeof(TotalAccum16));
426 memset(TotalAccum64, 0, sizeof(TotalAccum64));
427 TotalUnavail = TotalFreemap = 0;
428
429 env = getenv("HAMMER2_SHOW_ALL_VOLUME_HEADERS");
430 if (env != NULL) {
431 show_all_volume_headers = (int)strtol(env, NULL, 0);
432 if (errno)
433 show_all_volume_headers = 0;
434 errno = 0;
435 }
436 env = getenv("HAMMER2_SHOW_TAB");
437 if (env != NULL) {
438 show_tab = (int)strtol(env, NULL, 0);
439 if (errno || show_tab < 0 || show_tab > 8)
440 show_tab = 2;
441 errno = 0;
442 }
443 env = getenv("HAMMER2_SHOW_DEPTH");
444 if (env != NULL) {
445 show_depth = (int)strtol(env, NULL, 0);
446 if (errno || show_depth < 0)
447 show_depth = -1;
448 errno = 0;
449 }
450 env = getenv("HAMMER2_SHOW_MIN_MIRROR_TID");
451 if (env != NULL) {
452 show_min_mirror_tid = (hammer2_tid_t)strtoull(env, NULL, 16);
453 if (errno)
454 show_min_mirror_tid = 0;
455 errno = 0;
456 }
457 env = getenv("HAMMER2_SHOW_MIN_MODIFY_TID");
458 if (env != NULL) {
459 show_min_modify_tid = (hammer2_tid_t)strtoull(env, NULL, 16);
460 if (errno)
461 show_min_modify_tid = 0;
462 errno = 0;
463 }
464
465 hammer2_init_volumes(devpath, 1);
466 int all_volume_headers = VerboseOpt >= 3 || show_all_volume_headers;
467
468 /*
469 * Get best volume header for all volumes first.
470 */
471 volu_loff = 0;
472 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
473 for (j = 0; j < HAMMER2_NUM_VOLHDRS; ++j) {
474 off = j * HAMMER2_ZONE_BYTES64;
475 fd = hammer2_get_volume_fd(volu_loff);
476 lseek(fd, off, SEEK_SET);
477 if (read(fd, &media, HAMMER2_PBUFSIZE) ==
478 (ssize_t)HAMMER2_PBUFSIZE) {
479 if (bests[i] < 0 || best_mirror_tid <
480 media.voldata.mirror_tid) {
481 bests[i] = j;
482 best_mirror_tid = media.voldata.mirror_tid;
483 }
484 }
485 }
486 volu_loff = get_next_volume(&media.voldata, volu_loff);
487 }
488
489 /*
490 * Show the tree using the best volume header.
491 * -vvv will show the tree for all four volume headers.
492 */
493 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
494 volu_loff = next_volu_loff;
495 printf("%s\n", hammer2_get_volume_path(volu_loff));
496 for (j = 0; j < HAMMER2_NUM_VOLHDRS; ++j) {
497 bzero(&broot, sizeof(broot));
498 broot.data_off = (j * HAMMER2_ZONE_BYTES64) |
499 HAMMER2_PBUFRADIX;
500 off = broot.data_off & ~HAMMER2_OFF_MASK_RADIX;
501 fd = hammer2_get_volume_fd(volu_loff);
502 lseek(fd, off, SEEK_SET);
503 if (read(fd, &media, HAMMER2_PBUFSIZE) ==
504 (ssize_t)HAMMER2_PBUFSIZE) {
505 broot.mirror_tid = media.voldata.mirror_tid;
506 printf("Volume %d header %d: mirror_tid=%016jx\n",
507 media.voldata.volu_id, j,
508 (intmax_t)broot.mirror_tid);
509 if (all_volume_headers || bests[i] == j) {
510 switch(which) {
511 case 0:
512 broot.type = HAMMER2_BREF_TYPE_VOLUME;
513 show_bref(&media.voldata, 0, j,
514 &broot, 0);
515 next_volu_loff = -1;
516 break;
517 case 1:
518 broot.type = HAMMER2_BREF_TYPE_FREEMAP;
519 show_bref(&media.voldata, 0, j,
520 &broot, 0);
521 next_volu_loff = -1;
522 break;
523 default:
524 show_volhdr(&media.voldata, j);
525 next_volu_loff = get_next_volume(
526 &media.voldata, volu_loff);
527 break;
528 }
529 if (all_volume_headers && j != HAMMER2_NUM_VOLHDRS - 1)
530 printf("\n");
531 }
532 }
533 }
534 if (next_volu_loff == (hammer2_off_t)-1)
535 break;
536 if (i != HAMMER2_MAX_VOLUMES - 1)
537 printf("---------------------------------------------\n");
538 }
539
540 if (which == 1 && VerboseOpt < 3) {
541 printf("Total unallocated storage: %6.3fGB (%6.3fGB in 64KB chunks)\n",
542 (double)TotalAccum16[0] / GIG,
543 (double)TotalAccum64[0] / GIG);
544 printf("Total possibly free storage: %6.3fGB (%6.3fGB in 64KB chunks)\n",
545 (double)TotalAccum16[2] / GIG,
546 (double)TotalAccum64[2] / GIG);
547 printf("Total allocated storage: %6.3fGB (%6.3fGB in 64KB chunks)\n",
548 (double)TotalAccum16[3] / GIG,
549 (double)TotalAccum64[3] / GIG);
550 printf("Total unavailable storage: %6.3fGB\n",
551 (double)TotalUnavail / GIG);
552 printf("Total freemap storage: %6.3fGB\n",
553 (double)TotalFreemap / GIG);
554 }
555 hammer2_cleanup_volumes();
556
557 return 0;
558 }
559
560 static void
show_volhdr(hammer2_volume_data_t * voldata,int bi)561 show_volhdr(hammer2_volume_data_t *voldata, int bi)
562 {
563 uint32_t status;
564 uint32_t i;
565 char *str;
566 char *name;
567 char *buf;
568 uuid_t uuid;
569
570 printf("\nVolume %d header %d {\n", voldata->volu_id, bi);
571 printf(" magic 0x%016jx\n", (intmax_t)voldata->magic);
572 printf(" boot_beg 0x%016jx\n", (intmax_t)voldata->boot_beg);
573 printf(" boot_end 0x%016jx (%6.2fMB)\n",
574 (intmax_t)voldata->boot_end,
575 (double)(voldata->boot_end - voldata->boot_beg) /
576 (1024.0*1024.0));
577 printf(" aux_beg 0x%016jx\n", (intmax_t)voldata->aux_beg);
578 printf(" aux_end 0x%016jx (%6.2fMB)\n",
579 (intmax_t)voldata->aux_end,
580 (double)(voldata->aux_end - voldata->aux_beg) /
581 (1024.0*1024.0));
582 printf(" volu_size 0x%016jx (%6.2fGB)\n",
583 (intmax_t)voldata->volu_size,
584 (double)voldata->volu_size / GIG);
585 printf(" version %d\n", voldata->version);
586 printf(" flags 0x%08x\n", voldata->flags);
587 printf(" copyid %d\n", voldata->copyid);
588 printf(" freemap_vers %d\n", voldata->freemap_version);
589 printf(" peer_type %d\n", voldata->peer_type);
590 printf(" volu_id %d\n", voldata->volu_id);
591 printf(" nvolumes %d\n", voldata->nvolumes);
592
593 str = NULL;
594 uuid = voldata->fsid;
595 hammer2_uuid_to_str(&uuid, &str);
596 printf(" fsid %s\n", str);
597 free(str);
598
599 str = NULL;
600 name = NULL;
601 uuid = voldata->fstype;
602 hammer2_uuid_to_str(&uuid, &str);
603 printf(" fstype %s\n", str);
604 uuid_addr_lookup(&voldata->fstype, &name, &status);
605 if (name == NULL)
606 name = strdup("?");
607 printf(" (%s)\n", name);
608 free(name);
609 free(str);
610
611 printf(" allocator_size 0x%016jx (%6.2fGB)\n",
612 voldata->allocator_size,
613 (double)voldata->allocator_size / GIG);
614 printf(" allocator_free 0x%016jx (%6.2fGB)\n",
615 voldata->allocator_free,
616 (double)voldata->allocator_free / GIG);
617 printf(" allocator_beg 0x%016jx (%6.2fGB)\n",
618 voldata->allocator_beg,
619 (double)voldata->allocator_beg / GIG);
620
621 printf(" mirror_tid 0x%016jx\n", voldata->mirror_tid);
622 printf(" reserved0080 0x%016jx\n", voldata->reserved0080);
623 printf(" reserved0088 0x%016jx\n", voldata->reserved0088);
624 printf(" freemap_tid 0x%016jx\n", voldata->freemap_tid);
625 printf(" bulkfree_tid 0x%016jx\n", voldata->bulkfree_tid);
626 for (i = 0; i < nitems(voldata->reserved00A0); ++i) {
627 printf(" reserved00A0/%u 0x%016jx\n",
628 i, voldata->reserved00A0[0]);
629 }
630 printf(" total_size 0x%016jx\n", voldata->total_size);
631
632 printf(" copyexists ");
633 for (i = 0; i < nitems(voldata->copyexists); ++i)
634 printf(" 0x%02x", voldata->copyexists[i]);
635 printf("\n");
636
637 /*
638 * NOTE: Index numbers and ICRC_SECTn definitions are not matched,
639 * the ICRC for sector 0 actually uses the last index, for
640 * example.
641 *
642 * NOTE: The whole voldata CRC does not have to match critically
643 * as certain sub-areas of the volume header have their own
644 * CRCs.
645 */
646 printf("\n");
647 for (i = 0; i < nitems(voldata->icrc_sects); ++i) {
648 printf(" icrc_sects[%u] ", i);
649 switch(i) {
650 case HAMMER2_VOL_ICRC_SECT0:
651 printf("0x%08x/0x%08x",
652 hammer2_icrc32((char *)voldata +
653 HAMMER2_VOLUME_ICRC0_OFF,
654 HAMMER2_VOLUME_ICRC0_SIZE),
655 voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT0]);
656 if (hammer2_icrc32((char *)voldata +
657 HAMMER2_VOLUME_ICRC0_OFF,
658 HAMMER2_VOLUME_ICRC0_SIZE) ==
659 voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT0]) {
660 printf(" (OK)");
661 } else {
662 printf(" (FAILED)");
663 }
664 break;
665 case HAMMER2_VOL_ICRC_SECT1:
666 printf("0x%08x/0x%08x",
667 hammer2_icrc32((char *)voldata +
668 HAMMER2_VOLUME_ICRC1_OFF,
669 HAMMER2_VOLUME_ICRC1_SIZE),
670 voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT1]);
671 if (hammer2_icrc32((char *)voldata +
672 HAMMER2_VOLUME_ICRC1_OFF,
673 HAMMER2_VOLUME_ICRC1_SIZE) ==
674 voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT1]) {
675 printf(" (OK)");
676 } else {
677 printf(" (FAILED)");
678 }
679
680 break;
681 default:
682 printf("0x%08x (reserved)", voldata->icrc_sects[i]);
683 break;
684 }
685 printf("\n");
686 }
687 printf(" icrc_volhdr 0x%08x/0x%08x",
688 hammer2_icrc32((char *)voldata + HAMMER2_VOLUME_ICRCVH_OFF,
689 HAMMER2_VOLUME_ICRCVH_SIZE),
690 voldata->icrc_volheader);
691 if (hammer2_icrc32((char *)voldata + HAMMER2_VOLUME_ICRCVH_OFF,
692 HAMMER2_VOLUME_ICRCVH_SIZE) ==
693 voldata->icrc_volheader) {
694 printf(" (OK)\n");
695 } else {
696 printf(" (FAILED - not a critical error)\n");
697 }
698
699 /*
700 * The super-root and freemap blocksets (not recursed)
701 */
702 printf("\n");
703 printf(" sroot_blockset {\n");
704 for (i = 0; i < HAMMER2_SET_COUNT; ++i) {
705 show_bref(voldata, 16, i,
706 &voldata->sroot_blockset.blockref[i], 2);
707 }
708 printf(" }\n");
709
710 printf(" freemap_blockset {\n");
711 for (i = 0; i < HAMMER2_SET_COUNT; ++i) {
712 show_bref(voldata, 16, i,
713 &voldata->freemap_blockset.blockref[i], 2);
714 }
715 printf(" }\n");
716
717 buf = calloc(1, sizeof(voldata->volu_loff));
718 if (bcmp(buf, voldata->volu_loff, sizeof(voldata->volu_loff))) {
719 printf("\n");
720 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
721 hammer2_off_t loff = voldata->volu_loff[i];
722 if (loff != (hammer2_off_t)-1)
723 printf(" volu_loff[%d] 0x%016jx\n", i, loff);
724 }
725 }
726 free(buf);
727
728 printf("}\n");
729 }
730
731 static void
show_bref(hammer2_volume_data_t * voldata,int tab,int bi,hammer2_blockref_t * bref,int norecurse)732 show_bref(hammer2_volume_data_t *voldata, int tab, int bi,
733 hammer2_blockref_t *bref, int norecurse)
734 {
735 hammer2_media_data_t media;
736 hammer2_blockref_t *bscan;
737 hammer2_off_t tmp;
738 int i, bcount, namelen, failed, obrace, fd;
739 int type_pad;
740 size_t bytes;
741 const char *type_str;
742 char *str = NULL;
743 char check_str[32], comp_str[32];
744 uint8_t check_algo, comp_algo;
745 uint32_t cv;
746 uint64_t cv64;
747 static int init_tab = -1;
748 uuid_t uuid;
749
750 SHA256_CTX hash_ctx;
751 union {
752 uint8_t digest[SHA256_DIGEST_LENGTH];
753 uint64_t digest64[SHA256_DIGEST_LENGTH/8];
754 } u;
755
756 /* omit if smaller than mininum mirror_tid threshold */
757 if (bref->mirror_tid < show_min_mirror_tid)
758 return;
759 /* omit if smaller than mininum modify_tid threshold */
760 if (bref->modify_tid < show_min_modify_tid) {
761 if (bref->modify_tid)
762 return;
763 else if (bref->type == HAMMER2_BREF_TYPE_INODE && !bref->leaf_count)
764 return;
765 }
766
767 if (init_tab == -1)
768 init_tab = tab;
769
770 bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX);
771 if (bytes)
772 bytes = (size_t)1 << bytes;
773 if (bytes) {
774 hammer2_off_t io_off;
775 hammer2_off_t io_base;
776 size_t io_bytes;
777 size_t boff;
778
779 io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX;
780 io_base = io_off & ~(hammer2_off_t)(HAMMER2_LBUFSIZE - 1);
781 boff = io_off - io_base;
782
783 io_bytes = HAMMER2_LBUFSIZE;
784 while (io_bytes + boff < bytes)
785 io_bytes <<= 1;
786
787 if (io_bytes > sizeof(media)) {
788 printf("(bad block size %zu)\n", bytes);
789 return;
790 }
791 if (bref->type != HAMMER2_BREF_TYPE_DATA || VerboseOpt >= 1) {
792 fd = hammer2_get_volume_fd(io_off);
793 lseek(fd, io_base - hammer2_get_volume_offset(io_base),
794 SEEK_SET);
795 if (read(fd, &media, io_bytes) != (ssize_t)io_bytes) {
796 printf("(media read failed)\n");
797 return;
798 }
799 if (boff)
800 bcopy((char *)&media + boff, &media, bytes);
801 }
802 }
803
804 bscan = NULL;
805 bcount = 0;
806 namelen = 0;
807 failed = 0;
808 obrace = 1;
809
810 type_str = hammer2_breftype_to_str(bref->type);
811 type_pad = 8 - strlen(type_str);
812 if (type_pad < 0)
813 type_pad = 0;
814
815 switch(bref->type) {
816 case HAMMER2_BREF_TYPE_INODE:
817 assert(bytes);
818 if (!(media.ipdata.meta.op_flags & HAMMER2_OPFLAG_DIRECTDATA)) {
819 bscan = &media.ipdata.u.blockset.blockref[0];
820 bcount = HAMMER2_SET_COUNT;
821 }
822 break;
823 case HAMMER2_BREF_TYPE_INDIRECT:
824 assert(bytes);
825 bscan = &media.npdata[0];
826 bcount = bytes / sizeof(hammer2_blockref_t);
827 break;
828 case HAMMER2_BREF_TYPE_VOLUME:
829 bscan = &media.voldata.sroot_blockset.blockref[0];
830 bcount = HAMMER2_SET_COUNT;
831 break;
832 case HAMMER2_BREF_TYPE_FREEMAP:
833 bscan = &media.voldata.freemap_blockset.blockref[0];
834 bcount = HAMMER2_SET_COUNT;
835 break;
836 case HAMMER2_BREF_TYPE_FREEMAP_NODE:
837 assert(bytes);
838 bscan = &media.npdata[0];
839 bcount = bytes / sizeof(hammer2_blockref_t);
840 break;
841 }
842
843 if (QuietOpt > 0) {
844 tabprintf(tab,
845 "%s.%-3d %016jx %016jx/%-2d "
846 "vol=%d mir=%016jx mod=%016jx leafcnt=%d ",
847 type_str, bi, (intmax_t)bref->data_off,
848 (intmax_t)bref->key, (intmax_t)bref->keybits,
849 hammer2_get_volume_id(bref->data_off),
850 (intmax_t)bref->mirror_tid,
851 (intmax_t)bref->modify_tid,
852 bref->leaf_count);
853 } else {
854 tabprintf(tab, "%s.%-3d%*.*s %016jx %016jx/%-2d ",
855 type_str, bi, type_pad, type_pad, "",
856 (intmax_t)bref->data_off,
857 (intmax_t)bref->key, (intmax_t)bref->keybits);
858 /*if (norecurse > 1)*/ {
859 printf("\n");
860 tabprintf(tab + 13, "");
861 }
862 printf("vol=%d mir=%016jx mod=%016jx lfcnt=%d ",
863 hammer2_get_volume_id(bref->data_off),
864 (intmax_t)bref->mirror_tid, (intmax_t)bref->modify_tid,
865 bref->leaf_count);
866 if (/*norecurse > 1 && */ (bcount || bref->flags ||
867 bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE ||
868 bref->type == HAMMER2_BREF_TYPE_FREEMAP_LEAF)) {
869 printf("\n");
870 tabprintf(tab + 13, "");
871 }
872 }
873
874 if (bcount)
875 printf("bcnt=%d ", bcount);
876 if (bref->flags)
877 printf("flags=%02x ", bref->flags);
878 if (bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE ||
879 bref->type == HAMMER2_BREF_TYPE_FREEMAP_LEAF) {
880 printf("bigmask=%08x avail=%ju ",
881 bref->check.freemap.bigmask,
882 (uintmax_t)bref->check.freemap.avail);
883 }
884
885 /*
886 * Check data integrity in verbose mode, otherwise we are just doing
887 * a quick meta-data scan. Meta-data integrity is always checked.
888 * (Also see the check above that ensures the media data is loaded,
889 * otherwise there's no data to check!).
890 *
891 * WARNING! bref->check state may be used for other things when
892 * bref has no data (bytes == 0).
893 */
894 if (bytes &&
895 (bref->type != HAMMER2_BREF_TYPE_DATA || VerboseOpt >= 1)) {
896 if (!(QuietOpt > 0)) {
897 /*if (norecurse > 1)*/ {
898 printf("\n");
899 tabprintf(tab + 13, "");
900 }
901 }
902
903 check_algo = HAMMER2_DEC_CHECK(bref->methods);
904 strlcpy(check_str, hammer2_checkmode_to_str(check_algo),
905 sizeof(check_str));
906 comp_algo = HAMMER2_DEC_COMP(bref->methods);
907 strlcpy(comp_str, hammer2_compmode_to_str(comp_algo),
908 sizeof(comp_str));
909
910 switch(check_algo) {
911 case HAMMER2_CHECK_NONE:
912 printf("meth=%s|%s ", check_str, comp_str);
913 break;
914 case HAMMER2_CHECK_DISABLED:
915 printf("meth=%s|%s ", check_str, comp_str);
916 break;
917 case HAMMER2_CHECK_ISCSI32:
918 cv = hammer2_icrc32(&media, bytes);
919 if (bref->check.iscsi32.value != cv) {
920 printf("(icrc %s|%s %08x/%08x failed) ",
921 check_str, comp_str,
922 bref->check.iscsi32.value,
923 cv);
924 failed = 1;
925 } else {
926 printf("meth=%s|%s iscsi32=%08x ",
927 check_str, comp_str, cv);
928 }
929 break;
930 case HAMMER2_CHECK_XXHASH64:
931 cv64 = XXH64(&media, bytes, XXH_HAMMER2_SEED);
932 if (bref->check.xxhash64.value != cv64) {
933 printf("(xxhash64 %s|%s %016jx/%016jx failed) ",
934 check_str, comp_str,
935 bref->check.xxhash64.value,
936 cv64);
937 failed = 1;
938 } else {
939 printf("meth=%s|%s xxh=%016jx ",
940 check_str, comp_str, cv64);
941 }
942 break;
943 case HAMMER2_CHECK_SHA192:
944 SHA256_Init(&hash_ctx);
945 SHA256_Update(&hash_ctx, &media, bytes);
946 SHA256_Final(u.digest, &hash_ctx);
947 u.digest64[2] ^= u.digest64[3];
948 if (memcmp(u.digest, bref->check.sha192.data,
949 sizeof(bref->check.sha192.data))) {
950 printf("(sha192 %s:%s failed) ",
951 check_str, comp_str);
952 failed = 1;
953 } else {
954 printf("meth=%s|%s ", check_str, comp_str);
955 }
956 break;
957 case HAMMER2_CHECK_FREEMAP:
958 cv = hammer2_icrc32(&media, bytes);
959 if (bref->check.freemap.icrc32 != cv) {
960 printf("(fcrc %s|%s %08x/%08x failed) ",
961 check_str, comp_str,
962 bref->check.freemap.icrc32,
963 cv);
964 failed = 1;
965 } else {
966 printf("meth=%s|%s fcrc=%08x ",
967 check_str, comp_str, cv);
968 }
969 break;
970 }
971 }
972
973 tab += show_tab;
974
975 if (QuietOpt > 0) {
976 obrace = 0;
977 printf("\n");
978 goto skip_data;
979 }
980
981 switch(bref->type) {
982 case HAMMER2_BREF_TYPE_EMPTY:
983 if (norecurse)
984 printf("\n");
985 obrace = 0;
986 break;
987 case HAMMER2_BREF_TYPE_DIRENT:
988 printf("{\n");
989 if (bref->embed.dirent.namlen <= sizeof(bref->check.buf)) {
990 tabprintf(tab, "filename \"%*.*s\"\n",
991 bref->embed.dirent.namlen,
992 bref->embed.dirent.namlen,
993 bref->check.buf);
994 } else {
995 tabprintf(tab, "filename \"%*.*s\"\n",
996 bref->embed.dirent.namlen,
997 bref->embed.dirent.namlen,
998 media.buf);
999 }
1000 tabprintf(tab, "inum 0x%016jx\n",
1001 (uintmax_t)bref->embed.dirent.inum);
1002 tabprintf(tab, "nlen %d\n", bref->embed.dirent.namlen);
1003 tabprintf(tab, "type %s\n",
1004 hammer2_iptype_to_str(bref->embed.dirent.type));
1005 break;
1006 case HAMMER2_BREF_TYPE_INODE:
1007 printf("{\n");
1008 namelen = media.ipdata.meta.name_len;
1009 if (namelen > HAMMER2_INODE_MAXNAME)
1010 namelen = 0;
1011 tabprintf(tab, "filename \"%*.*s\"\n",
1012 namelen, namelen, media.ipdata.filename);
1013 tabprintf(tab, "version %d\n", media.ipdata.meta.version);
1014 if ((media.ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) ||
1015 media.ipdata.meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) {
1016 tabprintf(tab, "pfs_st %d (%s)\n",
1017 media.ipdata.meta.pfs_subtype,
1018 hammer2_pfssubtype_to_str(media.ipdata.meta.pfs_subtype));
1019 }
1020 tabprintf(tab, "uflags 0x%08x\n",
1021 media.ipdata.meta.uflags);
1022 if (media.ipdata.meta.rmajor || media.ipdata.meta.rminor) {
1023 tabprintf(tab, "rmajor %d\n",
1024 media.ipdata.meta.rmajor);
1025 tabprintf(tab, "rminor %d\n",
1026 media.ipdata.meta.rminor);
1027 }
1028 tabprintf(tab, "ctime %s\n",
1029 hammer2_time64_to_str(media.ipdata.meta.ctime, &str));
1030 tabprintf(tab, "mtime %s\n",
1031 hammer2_time64_to_str(media.ipdata.meta.mtime, &str));
1032 tabprintf(tab, "atime %s\n",
1033 hammer2_time64_to_str(media.ipdata.meta.atime, &str));
1034 tabprintf(tab, "btime %s\n",
1035 hammer2_time64_to_str(media.ipdata.meta.btime, &str));
1036 uuid = media.ipdata.meta.uid;
1037 tabprintf(tab, "uid %s\n",
1038 hammer2_uuid_to_str(&uuid, &str));
1039 uuid = media.ipdata.meta.gid;
1040 tabprintf(tab, "gid %s\n",
1041 hammer2_uuid_to_str(&uuid, &str));
1042 tabprintf(tab, "type %s\n",
1043 hammer2_iptype_to_str(media.ipdata.meta.type));
1044 tabprintf(tab, "opflgs 0x%02x\n",
1045 media.ipdata.meta.op_flags);
1046 tabprintf(tab, "capflgs 0x%04x\n",
1047 media.ipdata.meta.cap_flags);
1048 tabprintf(tab, "mode %-7o\n",
1049 media.ipdata.meta.mode);
1050 tabprintf(tab, "inum 0x%016jx\n",
1051 media.ipdata.meta.inum);
1052 tabprintf(tab, "size %ju ",
1053 (uintmax_t)media.ipdata.meta.size);
1054 if (media.ipdata.meta.op_flags & HAMMER2_OPFLAG_DIRECTDATA &&
1055 media.ipdata.meta.size <= HAMMER2_EMBEDDED_BYTES)
1056 printf("(embedded data)\n");
1057 else
1058 printf("\n");
1059 tabprintf(tab, "nlinks %ju\n",
1060 (uintmax_t)media.ipdata.meta.nlinks);
1061 tabprintf(tab, "iparent 0x%016jx\n",
1062 (uintmax_t)media.ipdata.meta.iparent);
1063 tabprintf(tab, "name_key 0x%016jx\n",
1064 (uintmax_t)media.ipdata.meta.name_key);
1065 tabprintf(tab, "name_len %u\n",
1066 media.ipdata.meta.name_len);
1067 tabprintf(tab, "ncopies %u\n",
1068 media.ipdata.meta.ncopies);
1069 tabprintf(tab, "compalg %s\n",
1070 hammer2_compmode_to_str(media.ipdata.meta.comp_algo));
1071 tabprintf(tab, "checkalg %s\n",
1072 hammer2_checkmode_to_str(media.ipdata.meta.check_algo));
1073 if ((media.ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) ||
1074 media.ipdata.meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) {
1075 tabprintf(tab, "pfs_nmas %u\n",
1076 media.ipdata.meta.pfs_nmasters);
1077 tabprintf(tab, "pfs_type %u (%s)\n",
1078 media.ipdata.meta.pfs_type,
1079 hammer2_pfstype_to_str(media.ipdata.meta.pfs_type));
1080 tabprintf(tab, "pfs_inum 0x%016jx\n",
1081 (uintmax_t)media.ipdata.meta.pfs_inum);
1082 uuid = media.ipdata.meta.pfs_clid;
1083 tabprintf(tab, "pfs_clid %s\n",
1084 hammer2_uuid_to_str(&uuid, &str));
1085 uuid = media.ipdata.meta.pfs_fsid;
1086 tabprintf(tab, "pfs_fsid %s\n",
1087 hammer2_uuid_to_str(&uuid, &str));
1088 tabprintf(tab, "pfs_lsnap_tid 0x%016jx\n",
1089 (uintmax_t)media.ipdata.meta.pfs_lsnap_tid);
1090 }
1091 tabprintf(tab, "data_quota %ju\n",
1092 (uintmax_t)media.ipdata.meta.data_quota);
1093 tabprintf(tab, "data_count %ju\n",
1094 (uintmax_t)bref->embed.stats.data_count);
1095 tabprintf(tab, "inode_quota %ju\n",
1096 (uintmax_t)media.ipdata.meta.inode_quota);
1097 tabprintf(tab, "inode_count %ju\n",
1098 (uintmax_t)bref->embed.stats.inode_count);
1099 break;
1100 case HAMMER2_BREF_TYPE_INDIRECT:
1101 printf("{\n");
1102 break;
1103 case HAMMER2_BREF_TYPE_DATA:
1104 printf("\n");
1105 obrace = 0;
1106 break;
1107 case HAMMER2_BREF_TYPE_VOLUME:
1108 printf("mirror_tid=%016jx freemap_tid=%016jx ",
1109 media.voldata.mirror_tid,
1110 media.voldata.freemap_tid);
1111 printf("{\n");
1112 break;
1113 case HAMMER2_BREF_TYPE_FREEMAP:
1114 printf("mirror_tid=%016jx freemap_tid=%016jx ",
1115 media.voldata.mirror_tid,
1116 media.voldata.freemap_tid);
1117 printf("{\n");
1118 break;
1119 case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
1120 printf("{\n");
1121 tmp = bref->data_off & ~HAMMER2_OFF_MASK_RADIX;
1122 tmp &= HAMMER2_SEGMASK;
1123 tmp /= HAMMER2_PBUFSIZE;
1124 assert(tmp >= HAMMER2_ZONE_FREEMAP_00);
1125 assert(tmp < HAMMER2_ZONE_FREEMAP_END);
1126 tmp -= HAMMER2_ZONE_FREEMAP_00;
1127 tmp /= HAMMER2_ZONE_FREEMAP_INC;
1128 tabprintf(tab, "rotation=%d\n", (int)tmp);
1129
1130 for (i = 0; i < HAMMER2_FREEMAP_COUNT; ++i) {
1131 hammer2_off_t data_off = bref->key +
1132 i * HAMMER2_FREEMAP_LEVEL0_SIZE;
1133 #if HAMMER2_BMAP_ELEMENTS != 8
1134 #error "cmd_debug.c: HAMMER2_BMAP_ELEMENTS expected to be 8"
1135 #endif
1136 tabprintf(tab + 4, "%016jx %04d.%04x linear=%06x avail=%06x "
1137 "%016jx %016jx %016jx %016jx "
1138 "%016jx %016jx %016jx %016jx\n",
1139 data_off, i, media.bmdata[i].class,
1140 media.bmdata[i].linear,
1141 media.bmdata[i].avail,
1142 media.bmdata[i].bitmapq[0],
1143 media.bmdata[i].bitmapq[1],
1144 media.bmdata[i].bitmapq[2],
1145 media.bmdata[i].bitmapq[3],
1146 media.bmdata[i].bitmapq[4],
1147 media.bmdata[i].bitmapq[5],
1148 media.bmdata[i].bitmapq[6],
1149 media.bmdata[i].bitmapq[7]);
1150 }
1151 tabprintf(tab, "}\n");
1152 break;
1153 case HAMMER2_BREF_TYPE_FREEMAP_NODE:
1154 printf("{\n");
1155 tmp = bref->data_off & ~HAMMER2_OFF_MASK_RADIX;
1156 tmp &= HAMMER2_SEGMASK;
1157 tmp /= HAMMER2_PBUFSIZE;
1158 assert(tmp >= HAMMER2_ZONE_FREEMAP_00);
1159 assert(tmp < HAMMER2_ZONE_FREEMAP_END);
1160 tmp -= HAMMER2_ZONE_FREEMAP_00;
1161 tmp /= HAMMER2_ZONE_FREEMAP_INC;
1162 tabprintf(tab, "rotation=%d\n", (int)tmp);
1163 break;
1164 default:
1165 printf("\n");
1166 obrace = 0;
1167 break;
1168 }
1169 if (str)
1170 free(str);
1171
1172 skip_data:
1173 /*
1174 * Update statistics.
1175 */
1176 switch(bref->type) {
1177 case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
1178 for (i = 0; i < HAMMER2_FREEMAP_COUNT; ++i) {
1179 hammer2_off_t data_off = bref->key +
1180 i * HAMMER2_FREEMAP_LEVEL0_SIZE;
1181 if (data_off >= voldata->aux_end &&
1182 data_off < hammer2_get_total_size()) {
1183 int j;
1184 for (j = 0; j < 4; ++j)
1185 count_blocks(&media.bmdata[i], j,
1186 &TotalAccum16[j],
1187 &TotalAccum64[j]);
1188 } else
1189 TotalUnavail += HAMMER2_FREEMAP_LEVEL0_SIZE;
1190 }
1191 TotalFreemap += HAMMER2_FREEMAP_LEVEL1_SIZE;
1192 break;
1193 default:
1194 break;
1195 }
1196
1197 /*
1198 * Recurse if norecurse == 0. If the CRC failed, pass norecurse = 1.
1199 * That is, if an indirect or inode fails we still try to list its
1200 * direct children to help with debugging, but go no further than
1201 * that because they are probably garbage.
1202 */
1203 if (show_depth == -1 || ((tab - init_tab) / show_tab) < show_depth) {
1204 for (i = 0; norecurse == 0 && i < bcount; ++i) {
1205 if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) {
1206 show_bref(voldata, tab, i, &bscan[i],
1207 failed);
1208 }
1209 }
1210 }
1211 tab -= show_tab;
1212 if (obrace) {
1213 if (bref->type == HAMMER2_BREF_TYPE_INODE)
1214 tabprintf(tab, "} (%s.%d, \"%*.*s\")\n",
1215 type_str, bi, namelen, namelen,
1216 media.ipdata.filename);
1217 else
1218 tabprintf(tab, "} (%s.%d)\n", type_str, bi);
1219 }
1220 }
1221
1222 static
1223 void
count_blocks(hammer2_bmap_data_t * bmap,int value,hammer2_off_t * accum16,hammer2_off_t * accum64)1224 count_blocks(hammer2_bmap_data_t *bmap, int value,
1225 hammer2_off_t *accum16, hammer2_off_t *accum64)
1226 {
1227 int i, j, bits;
1228 hammer2_bitmap_t value16, value64;
1229
1230 bits = (int)sizeof(hammer2_bitmap_t) * 8;
1231 assert(bits == 64);
1232
1233 value16 = value;
1234 assert(value16 < 4);
1235 value64 = (value16 << 6) | (value16 << 4) | (value16 << 2) | value16;
1236 assert(value64 < 256);
1237
1238 for (i = 0; i < HAMMER2_BMAP_ELEMENTS; ++i) {
1239 hammer2_bitmap_t bm = bmap->bitmapq[i];
1240 hammer2_bitmap_t bm_save = bm;
1241 hammer2_bitmap_t mask;
1242
1243 mask = 0x03; /* 2 bits per 16KB */
1244 for (j = 0; j < bits; j += 2) {
1245 if ((bm & mask) == value16)
1246 *accum16 += 16384;
1247 bm >>= 2;
1248 }
1249
1250 bm = bm_save;
1251 mask = 0xFF; /* 8 bits per 64KB chunk */
1252 for (j = 0; j < bits; j += 8) {
1253 if ((bm & mask) == value64)
1254 *accum64 += 65536;
1255 bm >>= 8;
1256 }
1257 }
1258 }
1259
1260 int
cmd_hash(int ac,const char ** av)1261 cmd_hash(int ac, const char **av)
1262 {
1263 int i;
1264
1265 for (i = 0; i < ac; ++i) {
1266 printf("%016jx %s\n",
1267 dirhash(av[i], strlen(av[i])),
1268 av[i]);
1269 }
1270 return(0);
1271 }
1272
1273 int
cmd_dhash(int ac,const char ** av)1274 cmd_dhash(int ac, const char **av)
1275 {
1276 char buf[1024]; /* 1K extended directory record */
1277 uint64_t hash;
1278 int i;
1279
1280 for (i = 0; i < ac; ++i) {
1281 bzero(buf, sizeof(buf));
1282 snprintf(buf, sizeof(buf), "%s", av[i]);
1283 hash = XXH64(buf, sizeof(buf), XXH_HAMMER2_SEED);
1284 printf("%016jx %s\n", hash, av[i]);
1285 }
1286 return(0);
1287 }
1288
1289 int
cmd_dumpchain(const char * path,u_int flags)1290 cmd_dumpchain(const char *path, u_int flags)
1291 {
1292 int dummy = (int)flags;
1293 int ecode = 0;
1294 int fd;
1295
1296 fd = open(path, O_RDONLY);
1297 if (fd >= 0) {
1298 if (ioctl(fd, HAMMER2IOC_DEBUG_DUMP, &dummy) < 0) {
1299 fprintf(stderr, "%s: %s\n", path, strerror(errno));
1300 ecode = 1;
1301 }
1302 close(fd);
1303 } else {
1304 fprintf(stderr, "unable to open %s\n", path);
1305 ecode = 1;
1306 }
1307 return ecode;
1308 }
1309
1310 static
1311 void
tabprintf(int tab,const char * ctl,...)1312 tabprintf(int tab, const char *ctl, ...)
1313 {
1314 va_list va;
1315
1316 printf("%*.*s", tab, tab, "");
1317 va_start(va, ctl);
1318 vprintf(ctl, va);
1319 va_end(va);
1320 }
1321