diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index 21113da2f03c..434a01acd01b 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -221,6 +221,7 @@ dump_debug_buffer(void) { if (dump_opt['G']) { (void) printf("\n"); + (void) fflush(stdout); zfs_dbgmsg_print("zdb"); } } diff --git a/cmd/ztest/ztest.c b/cmd/ztest/ztest.c index 1ac5a342eec8..6395ab21d0be 100644 --- a/cmd/ztest/ztest.c +++ b/cmd/ztest/ztest.c @@ -179,6 +179,7 @@ typedef struct ztest_shared_opts { uint64_t zo_metaslab_force_ganging; int zo_mmp_test; int zo_special_vdevs; + int zo_dump_dbgmsg; } ztest_shared_opts_t; static const ztest_shared_opts_t ztest_opts_defaults = { @@ -474,7 +475,6 @@ static kmutex_t ztest_checkpoint_lock; static pthread_rwlock_t ztest_name_lock; static boolean_t ztest_dump_core = B_TRUE; -static boolean_t ztest_dump_debug_buffer = B_FALSE; static boolean_t ztest_exiting; /* Global commit callback list */ @@ -523,10 +523,16 @@ _umem_logging_init(void) static void dump_debug_buffer(void) { - if (!ztest_dump_debug_buffer) + ssize_t ret __attribute__((unused)); + + if (!ztest_opts.zo_dump_dbgmsg) return; - (void) printf("\n"); + /* + * 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("ztest"); } @@ -581,10 +587,11 @@ fatal(int do_perror, char *message, ...) (void) fprintf(stderr, "%s\n", buf); fatal_msg = buf; /* to ease debugging */ - dump_debug_buffer(); - if (ztest_dump_core) abort(); + else + dump_debug_buffer(); + exit(3); } @@ -856,7 +863,7 @@ process_options(int argc, char **argv) usage(B_FALSE); break; case 'G': - ztest_dump_debug_buffer = B_TRUE; + zo->zo_dump_dbgmsg = 1; break; case 'h': usage(B_TRUE); diff --git a/include/sys/zfs_debug.h b/include/sys/zfs_debug.h index f3a936ae7ba0..f60932b5a86b 100644 --- a/include/sys/zfs_debug.h +++ b/include/sys/zfs_debug.h @@ -55,11 +55,12 @@ extern int zfs_dbgmsg_enable; #define ZFS_DEBUG_SET_ERROR (1 << 9) #define ZFS_DEBUG_INDIRECT_REMAP (1 << 10) -extern void __dprintf(const char *file, const char *func, +extern void __zfs_dbgmsg(char *buf); +extern void __dprintf(boolean_t dprint, const char *file, const char *func, int line, const char *fmt, ...); #define zfs_dbgmsg(...) \ if (zfs_dbgmsg_enable) \ - __dprintf(__FILE__, __func__, __LINE__, __VA_ARGS__) + __dprintf(B_FALSE, __FILE__, __func__, __LINE__, __VA_ARGS__) #ifdef ZFS_DEBUG /* @@ -69,7 +70,7 @@ extern void __dprintf(const char *file, const char *func, */ #define dprintf(...) \ if (zfs_flags & ZFS_DEBUG_DPRINTF) \ - __dprintf(__FILE__, __func__, __LINE__, __VA_ARGS__) + __dprintf(B_TRUE, __FILE__, __func__, __LINE__, __VA_ARGS__) #else #define dprintf(...) ((void)0) #endif /* ZFS_DEBUG */ diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 5baf52514a7b..4fcde3df7772 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -783,7 +783,8 @@ dprintf_setup(int *argc, char **argv) * ========================================================================= */ void -__dprintf(const char *file, const char *func, int line, const char *fmt, ...) +__dprintf(boolean_t dprint, const char *file, const char *func, + int line, const char *fmt, ...) { const char *newfile; va_list adx; @@ -798,9 +799,14 @@ __dprintf(const char *file, const char *func, int line, const char *fmt, ...) newfile = file; } - if (dprintf_print_all || - dprintf_find_string(newfile) || - dprintf_find_string(func)) { + if (dprint) { + /* dprintf messages are printed immediately */ + + if (!dprintf_print_all && + !dprintf_find_string(newfile) && + !dprintf_find_string(func)) + return; + /* Print out just the function name if requested */ flockfile(stdout); if (dprintf_find_string("pid")) @@ -813,11 +819,37 @@ __dprintf(const char *file, const char *func, int line, const char *fmt, ...) (void) printf("%llu ", gethrtime()); if (dprintf_find_string("long")) (void) printf("%s, line %d: ", newfile, line); - (void) printf("%s: ", func); + (void) printf("dprintf: %s: ", func); va_start(adx, fmt); (void) vprintf(fmt, adx); va_end(adx); funlockfile(stdout); + } else { + /* zfs_dbgmsg is logged for dumping later */ + size_t size; + char *buf, *nl; + int i; + + size = 1024; + buf = umem_alloc(size, UMEM_NOFAIL); + i = snprintf(buf, size, "%s:%d:%s(): ", newfile, line, func); + + if (i < size) { + va_start(adx, fmt); + (void) vsnprintf(buf + i, size - i, fmt, adx); + va_end(adx); + } + + /* + * Get rid of trailing newline. + */ + nl = strrchr(buf, '\n'); + if (nl != NULL) + *nl = '\0'; + + __zfs_dbgmsg(buf); + + umem_free(buf, size); } } diff --git a/module/zfs/zfs_debug.c b/module/zfs/zfs_debug.c index b5f93fd9bebb..e50552f6b7c9 100644 --- a/module/zfs/zfs_debug.c +++ b/module/zfs/zfs_debug.c @@ -124,11 +124,10 @@ __set_error(const char *file, const char *func, int line, int err) * $ echo 512 >/sys/module/zfs/parameters/zfs_flags */ if (zfs_flags & ZFS_DEBUG_SET_ERROR) - __dprintf(file, func, line, "error %lu", err); + __dprintf(B_FALSE, file, func, line, "error %lu", err); } -#ifdef _KERNEL -static void +void __zfs_dbgmsg(char *buf) { int size = sizeof (zfs_dbgmsg_t) + strlen(buf); @@ -144,8 +143,11 @@ __zfs_dbgmsg(char *buf) mutex_exit(&zfs_dbgmsgs.pl_lock); } +#ifdef _KERNEL + void -__dprintf(const char *file, const char *func, int line, const char *fmt, ...) +__dprintf(boolean_t dprint, const char *file, const char *func, + int line, const char *fmt, ...) { const char *newfile; va_list adx; @@ -153,6 +155,7 @@ __dprintf(const char *file, const char *func, int line, const char *fmt, ...) char *buf; char *nl; int i; + char *prefix = (dprint) ? "dprintf: " : ""; size = 1024; buf = kmem_alloc(size, KM_SLEEP); @@ -167,7 +170,7 @@ __dprintf(const char *file, const char *func, int line, const char *fmt, ...) newfile = file; } - i = snprintf(buf, size, "%s:%d:%s(): ", newfile, line, func); + i = snprintf(buf, size, "%s%s:%d:%s(): ", prefix, newfile, line, func); if (i < size) { va_start(adx, fmt); @@ -212,11 +215,24 @@ __dprintf(const char *file, const char *func, int line, const char *fmt, ...) void zfs_dbgmsg_print(const char *tag) { - (void) printf("ZFS_DBGMSG(%s):\n", tag); + ssize_t ret __attribute__((unused)); + + /* + * We use write() in this function instead of printf() + * so it is safe to call from a signal handler. + */ + ret = write(STDOUT_FILENO, "ZFS_DBGMSG(", 11); + ret = write(STDOUT_FILENO, tag, strlen(tag)); + ret = write(STDOUT_FILENO, "):\n", 3); + mutex_enter(&zfs_dbgmsgs.pl_lock); for (zfs_dbgmsg_t *zdm = list_head(&zfs_dbgmsgs.pl_list); zdm != NULL; - zdm = list_next(&zfs_dbgmsgs.pl_list, zdm)) - (void) printf("%s\n", zdm->zdm_msg); + zdm = list_next(&zfs_dbgmsgs.pl_list, zdm)) { + ret = write(STDOUT_FILENO, zdm->zdm_msg, + strlen(zdm->zdm_msg)); + ret = write(STDOUT_FILENO, "\n", 1); + } + mutex_exit(&zfs_dbgmsgs.pl_lock); } #endif /* _KERNEL */