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 <behlendorf1@llnl.gov> Signed-off-by: Rob Norris <rob.norris@klarasystems.com> Closes #16181
This commit is contained in:
parent
2a2e358475
commit
d06c8de748
|
@ -84,6 +84,9 @@
|
||||||
#include <sys/brt_impl.h>
|
#include <sys/brt_impl.h>
|
||||||
#include <zfs_comutil.h>
|
#include <zfs_comutil.h>
|
||||||
#include <sys/zstd/zstd.h>
|
#include <sys/zstd/zstd.h>
|
||||||
|
#if (__GLIBC__ && !__UCLIBC__)
|
||||||
|
#include <execinfo.h> /* for backtrace() */
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <libnvpair.h>
|
#include <libnvpair.h>
|
||||||
#include <libzutil.h>
|
#include <libzutil.h>
|
||||||
|
@ -926,11 +929,41 @@ usage(void)
|
||||||
static void
|
static void
|
||||||
dump_debug_buffer(void)
|
dump_debug_buffer(void)
|
||||||
{
|
{
|
||||||
if (dump_opt['G']) {
|
ssize_t ret __attribute__((unused));
|
||||||
(void) printf("\n");
|
|
||||||
(void) fflush(stdout);
|
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");
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8934,9 +8967,27 @@ main(int argc, char **argv)
|
||||||
char *spa_config_path_env, *objset_str;
|
char *spa_config_path_env, *objset_str;
|
||||||
boolean_t target_is_spa = B_TRUE, dataset_lookup = B_FALSE;
|
boolean_t target_is_spa = B_TRUE, dataset_lookup = B_FALSE;
|
||||||
nvlist_t *cfg = NULL;
|
nvlist_t *cfg = NULL;
|
||||||
|
struct sigaction action;
|
||||||
|
|
||||||
dprintf_setup(&argc, argv);
|
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
|
* If there is an environment variable SPA_CONFIG_PATH it overrides
|
||||||
* default spa_config_path setting. If -U flag is specified it will
|
* default spa_config_path setting. If -U flag is specified it will
|
||||||
|
|
Loading…
Reference in New Issue