From bd878fc99a65d56028b96b1c2535fff45df6e9a1 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 14 May 2012 22:40:10 -0700 Subject: [PATCH] hammer2 - Add media dump command, improve help output * Add 'hammer2 show '. This will dump the contents of the hammer2 filesystem structure on-media. * Improve usage() output. * Rename 'hammer2 debug ' to 'hammer2 shell '. --- sbin/hammer2/cmd_debug.c | 256 +++++++++++++++++++++++++++++++++++++++++-- sbin/hammer2/cmd_service.c | 2 +- sbin/hammer2/hammer2.h | 10 ++- sbin/hammer2/main.c | 52 +++++++-- sbin/hammer2/subs.c | 83 ++++++++++++++ 5 files changed, 377 insertions(+), 26 deletions(-) diff --git a/sbin/hammer2/cmd_debug.c b/sbin/hammer2/cmd_debug.c index 87add09..f648ab1 100644 --- a/sbin/hammer2/cmd_debug.c +++ b/sbin/hammer2/cmd_debug.c @@ -35,13 +35,19 @@ #include "hammer2.h" -static void debug_recv(hammer2_iocom_t *iocom); -static void debug_send(hammer2_iocom_t *iocom); -static void debug_tty(hammer2_iocom_t *iocom); -static void hammer2_debug_parse(hammer2_msg_t *msg, char *cmdbuf); +#define SHOW_TAB 2 + +static void shell_recv(hammer2_iocom_t *iocom); +static void shell_send(hammer2_iocom_t *iocom); +static void shell_tty(hammer2_iocom_t *iocom); +static void hammer2_shell_parse(hammer2_msg_t *msg, char *cmdbuf); + +/************************************************************************ + * SHELL * + ************************************************************************/ int -cmd_debug(const char *hostname) +cmd_shell(const char *hostname) { struct sockaddr_in lsin; struct hammer2_iocom iocom; @@ -94,7 +100,7 @@ cmd_debug(const char *hostname) msg = hammer2_allocmsg(&iocom, HAMMER2_DBG_SHELL, 0); hammer2_ioq_write(msg); - hammer2_iocom_core(&iocom, debug_recv, debug_send, debug_tty); + hammer2_iocom_core(&iocom, shell_recv, shell_send, shell_tty); fprintf(stderr, "debug: disconnected\n"); close(fd); return 0; @@ -106,7 +112,7 @@ cmd_debug(const char *hostname) */ static void -debug_recv(hammer2_iocom_t *iocom) +shell_recv(hammer2_iocom_t *iocom) { hammer2_msg_t *msg; @@ -157,14 +163,14 @@ debug_recv(hammer2_iocom_t *iocom) */ static void -debug_send(hammer2_iocom_t *iocom) +shell_send(hammer2_iocom_t *iocom) { hammer2_iocom_flush(iocom); } static void -debug_tty(hammer2_iocom_t *iocom) +shell_tty(hammer2_iocom_t *iocom) { hammer2_msg_t *msg; char buf[256]; @@ -193,7 +199,7 @@ debug_tty(hammer2_iocom_t *iocom) * then finish up by outputting another prompt. */ void -hammer2_debug_remote(hammer2_msg_t *msg) +hammer2_shell_remote(hammer2_msg_t *msg) { /* hammer2_iocom_t *iocom = msg->iocom; */ @@ -212,13 +218,13 @@ hammer2_debug_remote(hammer2_msg_t *msg) * Otherwise this is a command which we must process. * When we are finished we generate a final reply. */ - hammer2_debug_parse(msg, msg->aux_data); + hammer2_shell_parse(msg, msg->aux_data); hammer2_replymsg(msg, 0); } } static void -hammer2_debug_parse(hammer2_msg_t *msg, char *cmdbuf) +hammer2_shell_parse(hammer2_msg_t *msg, char *cmdbuf) { /* hammer2_iocom_t *iocom = msg->iocom; */ char *cmd = strsep(&cmdbuf, " \t"); @@ -255,3 +261,229 @@ msg_printf(hammer2_msg_t *msg, const char *ctl, ...) hammer2_ioq_write(rmsg); } + +/************************************************************************ + * SHOW * + ************************************************************************/ + +static void show_bref(int fd, int tab, int bi, hammer2_blockref_t *bref); +static void tabprintf(int tab, const char *ctl, ...); + +int +cmd_show(const char *devpath) +{ + hammer2_blockref_t broot; + int fd; + + fd = open(devpath, O_RDONLY); + if (fd < 0) { + perror("open"); + return 1; + } + bzero(&broot, sizeof(broot)); + broot.type = HAMMER2_BREF_TYPE_VOLUME; + broot.data_off = 0 | HAMMER2_PBUFRADIX; + show_bref(fd, 0, 0, &broot); + close(fd); + + return 0; +} + +static void +show_bref(int fd, int tab, int bi, hammer2_blockref_t *bref) +{ + hammer2_media_data_t media; + hammer2_blockref_t *bscan; + int bcount; + int i; + int didnl; + int obrace = 1; + size_t bytes; + const char *type_str; + char *str = NULL; + + switch(bref->type) { + case HAMMER2_BREF_TYPE_EMPTY: + type_str = "empty"; + break; + case HAMMER2_BREF_TYPE_INODE: + type_str = "inode"; + break; + case HAMMER2_BREF_TYPE_INDIRECT: + type_str = "indblk"; + break; + case HAMMER2_BREF_TYPE_DATA: + type_str = "data"; + break; + case HAMMER2_BREF_TYPE_VOLUME: + type_str = "volume"; + break; + default: + type_str = "unknown"; + break; + } + + + tabprintf(tab, "%s.%-3d %016jx/%-2d mir=%016jx mod=%016jx ", + type_str, bi, + bref->key, bref->keybits, + bref->mirror_tid, bref->modify_tid); + tab += SHOW_TAB; + + bytes = (size_t)1 << (bref->data_off & HAMMER2_OFF_MASK_RADIX); + if (bytes > sizeof(media)) { + printf("(bad block size %zd)\n", bytes); + return; + } + if (bref->type != HAMMER2_BREF_TYPE_DATA || VerboseOpt >= 1) { + lseek(fd, bref->data_off & ~HAMMER2_OFF_MASK_RADIX, 0); + if (read(fd, &media, bytes) != (ssize_t)bytes) { + printf("(media read failed)\n"); + return; + } + } + + bscan = NULL; + bcount = 0; + didnl = 0; + + switch(bref->type) { + case HAMMER2_BREF_TYPE_EMPTY: + obrace = 0; + break; + case HAMMER2_BREF_TYPE_INODE: + printf("{\n"); + if (media.ipdata.op_flags & HAMMER2_OPFLAG_DIRECTDATA) { + /* no blockrefs */ + } else { + bscan = &media.ipdata.u.blockset.blockref[0]; + bcount = HAMMER2_SET_COUNT; + } + tabprintf(tab, "filename \"%s\"\n", media.ipdata.filename); + tabprintf(tab, "version %d\n", media.ipdata.version); + tabprintf(tab, "uflags 0x%08x\n", + media.ipdata.uflags); + if (media.ipdata.rmajor || media.ipdata.rminor) { + tabprintf(tab, "rmajor %d\n", + media.ipdata.rmajor); + tabprintf(tab, "rminor %d\n", + media.ipdata.rminor); + } + tabprintf(tab, "ctime %s\n", + hammer2_time64_to_str(media.ipdata.ctime, &str)); + tabprintf(tab, "mtime %s\n", + hammer2_time64_to_str(media.ipdata.mtime, &str)); + tabprintf(tab, "atime %s\n", + hammer2_time64_to_str(media.ipdata.atime, &str)); + tabprintf(tab, "btime %s\n", + hammer2_time64_to_str(media.ipdata.btime, &str)); + tabprintf(tab, "uid %s\n", + hammer2_uuid_to_str(&media.ipdata.uid, &str)); + tabprintf(tab, "gid %s\n", + hammer2_uuid_to_str(&media.ipdata.gid, &str)); + tabprintf(tab, "type %s\n", + hammer2_iptype_to_str(media.ipdata.type)); + tabprintf(tab, "opflgs 0x%02x\n", + media.ipdata.op_flags); + tabprintf(tab, "capflgs 0x%04x\n", + media.ipdata.cap_flags); + tabprintf(tab, "mode %-7o\n", + media.ipdata.mode); + tabprintf(tab, "inum 0x%016jx\n", + media.ipdata.inum); + tabprintf(tab, "size %ju\n", + (uintmax_t)media.ipdata.size); + tabprintf(tab, "nlinks %ju\n", + (uintmax_t)media.ipdata.nlinks); + tabprintf(tab, "iparent 0x%016jx\n", + (uintmax_t)media.ipdata.iparent); + tabprintf(tab, "name_key 0x%016jx\n", + (uintmax_t)media.ipdata.name_key); + tabprintf(tab, "name_len %u\n", + media.ipdata.name_len); + tabprintf(tab, "ncopies %u\n", + media.ipdata.ncopies); + tabprintf(tab, "compalg %u\n", + media.ipdata.comp_algo); + if (media.ipdata.op_flags & HAMMER2_OPFLAG_PFSROOT) { + tabprintf(tab, "pfs_type %u (%s)\n", + media.ipdata.pfs_type, + hammer2_pfstype_to_str(media.ipdata.pfs_type)); + tabprintf(tab, "pfs_inum 0x%016jx\n", + (uintmax_t)media.ipdata.pfs_inum); + tabprintf(tab, "pfs_id %s\n", + hammer2_uuid_to_str(&media.ipdata.pfs_id, + &str)); + tabprintf(tab, "pfs_fsid %s\n", + hammer2_uuid_to_str(&media.ipdata.pfs_fsid, + &str)); + } + tabprintf(tab, "data_quota %ju\n", + (uintmax_t)media.ipdata.data_quota); + tabprintf(tab, "data_count %ju\n", + (uintmax_t)media.ipdata.data_count); + tabprintf(tab, "inode_quota %ju\n", + (uintmax_t)media.ipdata.inode_quota); + tabprintf(tab, "inode_count %ju\n", + (uintmax_t)media.ipdata.inode_count); + tabprintf(tab, "attr_tid 0x%016jx\n", + (uintmax_t)media.ipdata.attr_tid); + if (media.ipdata.type == HAMMER2_OBJTYPE_DIRECTORY) { + tabprintf(tab, "dirent_tid %016jx\n", + (uintmax_t)media.ipdata.dirent_tid); + } + break; + case HAMMER2_BREF_TYPE_INDIRECT: + bscan = &media.npdata.blockref[0]; + bcount = bytes / sizeof(hammer2_blockref_t); + didnl = 1; + printf("{\n"); + break; + case HAMMER2_BREF_TYPE_DATA: + if (VerboseOpt >= 2) { + printf("{\n"); + } else { + printf("\n"); + obrace = 0; + } + break; + case HAMMER2_BREF_TYPE_VOLUME: + bscan = &media.voldata.sroot_blockset.blockref[0]; + bcount = HAMMER2_SET_COUNT; + printf("{\n"); + break; + default: + break; + } + if (str) + free(str); + for (i = 0; i < bcount; ++i) { + if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) { + if (didnl == 0) { + printf("\n"); + didnl = 1; + } + show_bref(fd, tab, i, &bscan[i]); + } + } + tab -= SHOW_TAB; + if (obrace) { + if (bref->type == HAMMER2_BREF_TYPE_INODE) + tabprintf(tab, "} (%s.%d, \"%s\")\n", + type_str, bi, media.ipdata.filename); + else + tabprintf(tab, "} (%s.%d)\n", type_str,bi); + } +} + +static +void +tabprintf(int tab, const char *ctl, ...) +{ + va_list va; + + printf("%*.*s", tab, tab, ""); + va_start(va, ctl); + vprintf(ctl, va); + va_end(va); +} diff --git a/sbin/hammer2/cmd_service.c b/sbin/hammer2/cmd_service.c index fb4344d..5b0ebc7 100644 --- a/sbin/hammer2/cmd_service.c +++ b/sbin/hammer2/cmd_service.c @@ -215,7 +215,7 @@ master_link_rx(hammer2_iocom_t *iocom) break; case HAMMER2_DBG_SHELL: case HAMMER2_DBG_SHELL | HAMMER2_MSGF_REPLY: - hammer2_debug_remote(msg); + hammer2_shell_remote(msg); break; default: hammer2_replymsg(msg, HAMMER2_MSG_ERR_UNKNOWN); diff --git a/sbin/hammer2/hammer2.h b/sbin/hammer2/hammer2.h index 72fc488..e7642af 100644 --- a/sbin/hammer2/hammer2.h +++ b/sbin/hammer2/hammer2.h @@ -80,6 +80,7 @@ #define HAMMER2_PATH_REMOTE HAMMER2_DEFAULT_DIR "/remote" extern int DebugOpt; +extern int VerboseOpt; extern int NormalExit; int hammer2_ioctl_handle(const char *sel_path); @@ -97,7 +98,8 @@ int cmd_pfs_delete(const char *sel_path, const char *name); int cmd_service(void); int cmd_leaf(const char *sel_path); -int cmd_debug(const char *hostname); +int cmd_shell(const char *hostname); +int cmd_show(const char *devpath); int cmd_rsainit(const char *dir_path); int cmd_rsaenc(const char **keys, int nkeys); int cmd_rsadec(const char **keys, int nkeys); @@ -133,6 +135,10 @@ int hammer2_crypto_encrypt(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq, void hammer2_crypto_encrypt_wrote(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq, int nact); +const char *hammer2_time64_to_str(uint64_t htime64, char **strp); +const char *hammer2_uuid_to_str(uuid_t *uuid, char **strp); +const char *hammer2_iptype_to_str(uint8_t type); +const char *hammer2_pfstype_to_str(uint8_t type); -void hammer2_debug_remote(hammer2_msg_t *msg); +void hammer2_shell_remote(hammer2_msg_t *msg); void msg_printf(hammer2_msg_t *msg, const char *ctl, ...); diff --git a/sbin/hammer2/main.c b/sbin/hammer2/main.c index 2be4662..a43f5cd 100644 --- a/sbin/hammer2/main.c +++ b/sbin/hammer2/main.c @@ -38,6 +38,7 @@ static void usage(int code); int DebugOpt; +int VerboseOpt; int NormalExit = 1; /* if set to 0 main() has to pthread_exit() */ int @@ -57,11 +58,14 @@ main(int ac, char **av) /* * Core options */ - while ((ch = getopt(ac, av, "adqs:t:u:")) != -1) { + while ((ch = getopt(ac, av, "adqs:t:u:v")) != -1) { switch(ch) { case 'a': all_opt = 1; break; + case 'd': + DebugOpt = 1; + break; case 'q': /* * Quick mode - do not block verifying certain @@ -102,8 +106,8 @@ main(int ac, char **av) */ uuid_str = optarg; break; - case 'd': - DebugOpt = 1; + case 'v': + ++VerboseOpt; break; default: fprintf(stderr, "Unknown option: %c\n", ch); @@ -147,32 +151,32 @@ main(int ac, char **av) * Get status of PFS and its connections (-a for all PFSs) */ ecode = cmd_remote_status(sel_path, all_opt); - } else if (strcmp(av[0], "pfs_list") == 0) { + } else if (strcmp(av[0], "pfs-list") == 0) { /* * List all PFSs */ ecode = cmd_pfs_list(sel_path); - } else if (strcmp(av[0], "pfs_create") == 0) { + } else if (strcmp(av[0], "pfs-create") == 0) { /* * Create new PFS using pfs_type */ if (ac < 2) { - fprintf(stderr, "pfs_create: requires name\n"); + fprintf(stderr, "pfs-create: requires name\n"); usage(1); } ecode = cmd_pfs_create(sel_path, av[1], pfs_type, uuid_str); - } else if (strcmp(av[0], "pfs_delete") == 0) { + } else if (strcmp(av[0], "pfs-delete") == 0) { /* * Delete a PFS by name */ if (ac < 2) { - fprintf(stderr, "pfs_delete: requires name\n"); + fprintf(stderr, "pfs-delete: requires name\n"); usage(1); } ecode = cmd_pfs_delete(sel_path, av[1]); } else if (strcmp(av[0], "snapshot") == 0) { /* - * Create snapshot with optional pfs_type and optional + * Create snapshot with optional pfs-type and optional * label override. */ } else if (strcmp(av[0], "service") == 0) { @@ -207,12 +211,12 @@ main(int ac, char **av) * complexity of the HAMMER2 VFS kernel code. */ ecode = cmd_leaf(sel_path); - } else if (strcmp(av[0], "debug") == 0) { + } else if (strcmp(av[0], "shell") == 0) { /* * Connect to the command line monitor in the hammer2 master * node for the machine using HAMMER2_DBG_SHELL messages. */ - ecode = cmd_debug((ac < 2) ? NULL : av[1]); + ecode = cmd_shell((ac < 2) ? NULL : av[1]); } else if (strcmp(av[0], "rsainit") == 0) { /* * Initialize a RSA keypair. If no target directory is @@ -258,6 +262,17 @@ main(int ac, char **av) } else { ecode = cmd_rsadec((const char **)&av[1], ac - 1); } + } else if (strcmp(av[0], "show") == 0) { + /* + * Raw dump of filesystem. Use -v to check all crc's, and + * -vv to dump bulk file data. + */ + if (ac != 2) { + fprintf(stderr, "show: requires device path\n"); + usage(1); + } else { + cmd_show(av[1]); + } } else { fprintf(stderr, "Unrecognized command: %s\n", av[0]); usage(1); @@ -283,6 +298,21 @@ usage(int code) fprintf(stderr, "hammer2 [-s path] command...\n" " -s path Select filesystem\n" + " -t type PFS type for pfs-create\n" + " -u uuid uuid for pfs-create\n" + "\n" + " connect Add cluster link\n" + " disconnect Del cluster link\n" + " status Report cluster status\n" + " pfs-list List PFSs\n" + " pfs-create