Skip to content

Commit

Permalink
Fix dbgmsg printing in ztest and zdb
Browse files Browse the repository at this point in the history
This patch resolves a problem where the -G option in both zdb and
ztest would cause the code to call __dprintf() to print zfs_dbgmsg
output. This function was not properly wired to add messages to the
dbgmsg log as it is in userspace and so the messages were simply
dropped. This patch also tries to add some degree of distinction to
dprintf() (which now prints directly to stdout) and zfs_dbgmsg()
(which adds messages to an internal list that can be dumped with
zfs_dbgmsg_print()).

In addition, this patch corrects an issue where ztest used a global
variable to decide whether to dump the dbgmsg buffer on a crash.
This did not work because ztest spins up more instances of itself
using execv(), which did not copy the global variable to the new
process. The option has been moved to the ztest_shared_opts_t
which already exists for interprocess communication.

This patch also changes zfs_dbgmsg_print() to use write() calls
instead of printf() so that it will not fail when used in a signal
handler.

TEST_ZTEST_TIMEOUT=3600

Signed-off-by: Tom Caputi <tcaputi@datto.com>
  • Loading branch information
Tom Caputi committed Oct 17, 2018
1 parent f34d50f commit 9f4ce5f
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 22 deletions.
1 change: 1 addition & 0 deletions cmd/zdb/zdb.c
Expand Up @@ -221,6 +221,7 @@ dump_debug_buffer(void)
{
if (dump_opt['G']) {
(void) printf("\n");
(void) fflush(stdout);
zfs_dbgmsg_print("zdb");
}
}
Expand Down
19 changes: 13 additions & 6 deletions cmd/ztest/ztest.c
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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");
}

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
Expand Down
7 changes: 4 additions & 3 deletions include/sys/zfs_debug.h
Expand Up @@ -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
/*
Expand All @@ -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 */
Expand Down
42 changes: 37 additions & 5 deletions lib/libzpool/kernel.c
Expand Up @@ -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;
Expand All @@ -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"))
Expand All @@ -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);
}
}

Expand Down
32 changes: 24 additions & 8 deletions module/zfs/zfs_debug.c
Expand Up @@ -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);
Expand All @@ -144,15 +143,19 @@ __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;
size_t size;
char *buf;
char *nl;
int i;
char *prefix = (dprint) ? "dprintf: " : "";

size = 1024;
buf = kmem_alloc(size, KM_SLEEP);
Expand All @@ -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);
Expand Down Expand Up @@ -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 */
Expand Down

0 comments on commit 9f4ce5f

Please sign in to comment.