From 495b25a91a8f29aeec9e2965752a1fc9b9569583 Mon Sep 17 00:00:00 2001
From: Richard Yao <ryao@gentoo.org>
Date: Tue, 8 Oct 2013 22:37:38 -0400
Subject: [PATCH] Add missing code to zfs_debug.{c,h}

This is required to make Illumos 3962 merge.

Signed-off-by: Richard Yao <ryao@gentoo.org>
---
 include/sys/zfs_debug.h | 33 +++++++++++++++++---
 module/zfs/zfs_debug.c  | 68 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+), 4 deletions(-)

diff --git a/include/sys/zfs_debug.h b/include/sys/zfs_debug.h
index 7632d7420c14..41e8c08a15fe 100644
--- a/include/sys/zfs_debug.h
+++ b/include/sys/zfs_debug.h
@@ -20,11 +20,16 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  */
 
 #ifndef _SYS_ZFS_DEBUG_H
 #define	_SYS_ZFS_DEBUG_H
 
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
 #ifndef TRUE
 #define	TRUE 1
 #endif
@@ -36,6 +41,7 @@
 /*
  * ZFS debugging - Always enabled for user space builds.
  */
+
 #if !defined(ZFS_DEBUG) && !defined(_KERNEL)
 #define	ZFS_DEBUG
 #endif
@@ -75,9 +81,28 @@ extern int zfs_recover;
 
 #endif /* _KERNEL */
 
-void zfs_panic_recover(const char *fmt, ...);
-#define	zfs_dbgmsg(...)	dprintf(__VA_ARGS__)
-void zfs_dbgmsg_init(void);
-void zfs_dbgmsg_fini(void);
+extern void zfs_panic_recover(const char *fmt, ...);
+
+typedef struct zfs_dbgmsg {
+	list_node_t zdm_node;
+	time_t zdm_timestamp;
+	char zdm_msg[1]; /* variable length allocation */
+} zfs_dbgmsg_t;
+
+extern void zfs_dbgmsg_init(void);
+extern void zfs_dbgmsg_fini(void);
+#if defined(_KERNEL) && defined(__linux__)
+#define        zfs_dbgmsg(...) dprintf(__VA_ARGS__)
+#else
+extern void zfs_dbgmsg(const char *fmt, ...);
+#endif
+
+#ifndef _KERNEL
+extern int dprintf_find_string(const char *string);
+#endif
+
+#ifdef	__cplusplus
+}
+#endif
 
 #endif	/* _SYS_ZFS_DEBUG_H */
diff --git a/module/zfs/zfs_debug.c b/module/zfs/zfs_debug.c
index ad611ac91da8..29423303fb6e 100644
--- a/module/zfs/zfs_debug.c
+++ b/module/zfs/zfs_debug.c
@@ -25,6 +25,13 @@
 
 #include <sys/zfs_context.h>
 
+#if !defined(_KERNEL) || !defined(__linux__)
+list_t zfs_dbgmsgs;
+int zfs_dbgmsg_size;
+kmutex_t zfs_dbgmsgs_lock;
+int zfs_dbgmsg_maxsize = 1<<20; /* 1MB */
+#endif
+
 /*
  * Enable various debugging features.
  */
@@ -57,6 +64,12 @@ zfs_panic_recover(const char *fmt, ...)
 void
 zfs_dbgmsg_init(void)
 {
+#if !defined(_KERNEL) || !defined(__linux__)
+	list_create(&zfs_dbgmsgs, sizeof (zfs_dbgmsg_t),
+	    offsetof(zfs_dbgmsg_t, zdm_node));
+	mutex_init(&zfs_dbgmsgs_lock, NULL, MUTEX_DEFAULT, NULL);
+#endif
+
 	if (zfs_flags == 0) {
 #if defined(_KERNEL)
 		zfs_flags = ZFS_DEBUG_DPRINTF;
@@ -71,9 +84,64 @@ zfs_dbgmsg_init(void)
 void
 zfs_dbgmsg_fini(void)
 {
+#if !defined(_KERNEL) || !defined(__linux__)
+	zfs_dbgmsg_t *zdm;
+
+	while ((zdm = list_remove_head(&zfs_dbgmsgs)) != NULL) {
+		int size = sizeof (zfs_dbgmsg_t) + strlen(zdm->zdm_msg);
+		kmem_free(zdm, size);
+		zfs_dbgmsg_size -= size;
+	}
+	mutex_destroy(&zfs_dbgmsgs_lock);
+	ASSERT0(zfs_dbgmsg_size);
+#endif
 	return;
 }
 
+#if !defined(_KERNEL) || !defined(__linux__)
+/*
+ * Print these messages by running:
+ * echo ::zfs_dbgmsg | mdb -k
+ *
+ * Monitor these messages by running:
+ * 	dtrace -q -n 'zfs-dbgmsg{printf("%s\n", stringof(arg0))}'
+ */
+void
+zfs_dbgmsg(const char *fmt, ...)
+{
+	int size;
+	va_list adx;
+	zfs_dbgmsg_t *zdm;
+
+	va_start(adx, fmt);
+	size = vsnprintf(NULL, 0, fmt, adx);
+	va_end(adx);
+
+	/*
+	 * There is one byte of string in sizeof (zfs_dbgmsg_t), used
+	 * for the terminating null.
+	 */
+	zdm = kmem_alloc(sizeof (zfs_dbgmsg_t) + size, KM_SLEEP);
+	zdm->zdm_timestamp = gethrestime_sec();
+
+	va_start(adx, fmt);
+	(void) vsnprintf(zdm->zdm_msg, size + 1, fmt, adx);
+	va_end(adx);
+
+	DTRACE_PROBE1(zfs__dbgmsg, char *, zdm->zdm_msg);
+
+	mutex_enter(&zfs_dbgmsgs_lock);
+	list_insert_tail(&zfs_dbgmsgs, zdm);
+	zfs_dbgmsg_size += sizeof (zfs_dbgmsg_t) + size;
+	while (zfs_dbgmsg_size > zfs_dbgmsg_maxsize) {
+		zdm = list_remove_head(&zfs_dbgmsgs);
+		size = sizeof (zfs_dbgmsg_t) + strlen(zdm->zdm_msg);
+		kmem_free(zdm, size);
+		zfs_dbgmsg_size -= size;
+	}
+	mutex_exit(&zfs_dbgmsgs_lock);
+}
+#endif
 
 #if defined(_KERNEL)
 module_param(zfs_flags, int, 0644);