diff options
author | Rob Norris <[email protected]> | 2024-05-10 09:56:48 +1000 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2024-05-14 09:48:23 -0700 |
commit | 91c46d4399e42b2b14ae65ae8637061b67adbd82 (patch) | |
tree | 9ee011b4e0056db500da170b9ff48fafcb63d32b /cmd/zdb | |
parent | 0a543db37111c28085043da89e452ea6b131c019 (diff) |
zdb: bring crash handling over from ztest
ztest has a very nice ability to show a backtrace when there's an
unexpected crash. zdb is used often enough on corrupted data and can
blow up too, so nice output is useful there too.
Sponsored-by: Klara, Inc.
Sponsored-by: Wasabi Technology, Inc.
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Rob Norris <[email protected]>
Closes #16181
Diffstat (limited to 'cmd/zdb')
-rw-r--r-- | cmd/zdb/zdb.c | 61 |
1 files changed, 56 insertions, 5 deletions
diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index 797ae34b6..f3274a65d 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -85,6 +85,9 @@ #include <sys/brt_impl.h> #include <zfs_comutil.h> #include <sys/zstd/zstd.h> +#if (__GLIBC__ && !__UCLIBC__) +#include <execinfo.h> /* for backtrace() */ +#endif #include <libnvpair.h> #include <libzutil.h> @@ -828,11 +831,41 @@ usage(void) static void dump_debug_buffer(void) { - if (dump_opt['G']) { - (void) printf("\n"); - (void) fflush(stdout); - zfs_dbgmsg_print("zdb"); - } + ssize_t ret __attribute__((unused)); + + if (!dump_opt['G']) + return; + /* + * We use write() instead of printf() so that this function + * is safe to call from a signal handler. + */ + ret = write(STDOUT_FILENO, "\n", 1); + zfs_dbgmsg_print("zdb"); +} + +#define BACKTRACE_SZ 100 + +static void sig_handler(int signo) +{ + struct sigaction action; +#if (__GLIBC__ && !__UCLIBC__) /* backtrace() is a GNU extension */ + int nptrs; + void *buffer[BACKTRACE_SZ]; + + nptrs = backtrace(buffer, BACKTRACE_SZ); + backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO); +#endif + dump_debug_buffer(); + + /* + * Restore default action and re-raise signal so SIGSEGV and + * SIGABRT can trigger a core dump. + */ + action.sa_handler = SIG_DFL; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + (void) sigaction(signo, &action, NULL); + raise(signo); } /* @@ -8899,10 +8932,28 @@ main(int argc, char **argv) char *spa_config_path_env, *objset_str; boolean_t target_is_spa = B_TRUE, dataset_lookup = B_FALSE; nvlist_t *cfg = NULL; + struct sigaction action; dprintf_setup(&argc, argv); /* + * Set up signal handlers, so if we crash due to bad on-disk data we + * can get more info. Unlike ztest, we don't bail out if we can't set + * up signal handlers, because zdb is very useful without them. + */ + action.sa_handler = sig_handler; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + if (sigaction(SIGSEGV, &action, NULL) < 0) { + (void) fprintf(stderr, "zdb: cannot catch SIGSEGV: %s\n", + strerror(errno)); + } + if (sigaction(SIGABRT, &action, NULL) < 0) { + (void) fprintf(stderr, "zdb: cannot catch SIGABRT: %s\n", + strerror(errno)); + } + + /* * If there is an environment variable SPA_CONFIG_PATH it overrides * default spa_config_path setting. If -U flag is specified it will * override this environment variable settings once again. |