aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/zdb
diff options
context:
space:
mode:
authorRob Norris <[email protected]>2024-05-10 09:56:48 +1000
committerBrian Behlendorf <[email protected]>2024-05-14 09:48:23 -0700
commit91c46d4399e42b2b14ae65ae8637061b67adbd82 (patch)
tree9ee011b4e0056db500da170b9ff48fafcb63d32b /cmd/zdb
parent0a543db37111c28085043da89e452ea6b131c019 (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.c61
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.