xref: /freebsd/sys/contrib/openzfs/module/os/linux/zfs/zfs_debug.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or https://opensource.org/licenses/CDDL-1.0.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
25  */
26 
27 #include <sys/zfs_context.h>
28 #include <sys/trace_zfs.h>
29 
30 typedef struct zfs_dbgmsg {
31 	procfs_list_node_t	zdm_node;
32 	uint64_t		zdm_timestamp;
33 	uint_t			zdm_size;
34 	char			zdm_msg[]; /* variable length allocation */
35 } zfs_dbgmsg_t;
36 
37 static procfs_list_t zfs_dbgmsgs;
38 static uint_t zfs_dbgmsg_size = 0;
39 static uint_t zfs_dbgmsg_maxsize = 4<<20; /* 4MB */
40 
41 /*
42  * Internal ZFS debug messages are enabled by default.
43  *
44  * # Print debug messages
45  * cat /proc/spl/kstat/zfs/dbgmsg
46  *
47  * # Disable the kernel debug message log.
48  * echo 0 > /sys/module/zfs/parameters/zfs_dbgmsg_enable
49  *
50  * # Clear the kernel debug message log.
51  * echo 0 >/proc/spl/kstat/zfs/dbgmsg
52  */
53 int zfs_dbgmsg_enable = B_TRUE;
54 
55 static int
zfs_dbgmsg_show_header(struct seq_file * f)56 zfs_dbgmsg_show_header(struct seq_file *f)
57 {
58 	seq_printf(f, "%-12s %-8s\n", "timestamp", "message");
59 	return (0);
60 }
61 
62 static int
zfs_dbgmsg_show(struct seq_file * f,void * p)63 zfs_dbgmsg_show(struct seq_file *f, void *p)
64 {
65 	zfs_dbgmsg_t *zdm = (zfs_dbgmsg_t *)p;
66 	seq_printf(f, "%-12llu %-s\n",
67 	    (u_longlong_t)zdm->zdm_timestamp, zdm->zdm_msg);
68 	return (0);
69 }
70 
71 static void
zfs_dbgmsg_purge(uint_t max_size)72 zfs_dbgmsg_purge(uint_t max_size)
73 {
74 	while (zfs_dbgmsg_size > max_size) {
75 		zfs_dbgmsg_t *zdm = list_remove_head(&zfs_dbgmsgs.pl_list);
76 		if (zdm == NULL)
77 			return;
78 
79 		uint_t size = zdm->zdm_size;
80 		kmem_free(zdm, size);
81 		zfs_dbgmsg_size -= size;
82 	}
83 }
84 
85 static int
zfs_dbgmsg_clear(procfs_list_t * procfs_list)86 zfs_dbgmsg_clear(procfs_list_t *procfs_list)
87 {
88 	(void) procfs_list;
89 	mutex_enter(&zfs_dbgmsgs.pl_lock);
90 	zfs_dbgmsg_purge(0);
91 	mutex_exit(&zfs_dbgmsgs.pl_lock);
92 	return (0);
93 }
94 
95 void
zfs_dbgmsg_init(void)96 zfs_dbgmsg_init(void)
97 {
98 	procfs_list_install("zfs",
99 	    NULL,
100 	    "dbgmsg",
101 	    0600,
102 	    &zfs_dbgmsgs,
103 	    zfs_dbgmsg_show,
104 	    zfs_dbgmsg_show_header,
105 	    zfs_dbgmsg_clear,
106 	    offsetof(zfs_dbgmsg_t, zdm_node));
107 }
108 
109 void
zfs_dbgmsg_fini(void)110 zfs_dbgmsg_fini(void)
111 {
112 	procfs_list_uninstall(&zfs_dbgmsgs);
113 	zfs_dbgmsg_purge(0);
114 
115 	procfs_list_destroy(&zfs_dbgmsgs);
116 }
117 
118 void
__set_error(const char * file,const char * func,int line,int err)119 __set_error(const char *file, const char *func, int line, int err)
120 {
121 	/*
122 	 * To enable this:
123 	 *
124 	 * $ echo 512 >/sys/module/zfs/parameters/zfs_flags
125 	 */
126 	if (zfs_flags & ZFS_DEBUG_SET_ERROR)
127 		__dprintf(B_FALSE, file, func, line, "error %lu",
128 		    (ulong_t)err);
129 }
130 
131 void
__zfs_dbgmsg(char * buf)132 __zfs_dbgmsg(char *buf)
133 {
134 	uint_t size = sizeof (zfs_dbgmsg_t) + strlen(buf) + 1;
135 	zfs_dbgmsg_t *zdm = kmem_zalloc(size, KM_SLEEP);
136 	zdm->zdm_size = size;
137 	zdm->zdm_timestamp = gethrestime_sec();
138 	strcpy(zdm->zdm_msg, buf);
139 
140 	mutex_enter(&zfs_dbgmsgs.pl_lock);
141 	procfs_list_add(&zfs_dbgmsgs, zdm);
142 	zfs_dbgmsg_size += size;
143 	zfs_dbgmsg_purge(zfs_dbgmsg_maxsize);
144 	mutex_exit(&zfs_dbgmsgs.pl_lock);
145 }
146 
147 void
__dprintf(boolean_t dprint,const char * file,const char * func,int line,const char * fmt,...)148 __dprintf(boolean_t dprint, const char *file, const char *func,
149     int line, const char *fmt, ...)
150 {
151 	const char *newfile;
152 	va_list adx;
153 	size_t size;
154 	char *buf;
155 	char *nl;
156 	int i;
157 	char *prefix = (dprint) ? "dprintf: " : "";
158 
159 	size = 1024;
160 	buf = kmem_alloc(size, KM_SLEEP);
161 
162 	/*
163 	 * Get rid of annoying prefix to filename.
164 	 */
165 	newfile = strrchr(file, '/');
166 	if (newfile != NULL) {
167 		newfile = newfile + 1; /* Get rid of leading / */
168 	} else {
169 		newfile = file;
170 	}
171 
172 	i = snprintf(buf, size, "%px %s%s:%d:%s(): ",
173 	    curthread, prefix, newfile, line, func);
174 
175 	if (i < size) {
176 		va_start(adx, fmt);
177 		(void) vsnprintf(buf + i, size - i, fmt, adx);
178 		va_end(adx);
179 	}
180 
181 	/*
182 	 * Get rid of trailing newline for dprintf logs.
183 	 */
184 	if (dprint && buf[0] != '\0') {
185 		nl = &buf[strlen(buf) - 1];
186 		if (*nl == '\n')
187 			*nl = '\0';
188 	}
189 
190 	/*
191 	 * To get this data enable the zfs__dprintf trace point as shown:
192 	 *
193 	 * # Enable zfs__dprintf tracepoint, clear the tracepoint ring buffer
194 	 * $ echo 1 > /sys/kernel/debug/tracing/events/zfs/enable
195 	 * $ echo 0 > /sys/kernel/debug/tracing/trace
196 	 *
197 	 * # Dump the ring buffer.
198 	 * $ cat /sys/kernel/debug/tracing/trace
199 	 */
200 	DTRACE_PROBE1(zfs__dprintf, char *, buf);
201 
202 	/*
203 	 * To get this data:
204 	 *
205 	 * $ cat /proc/spl/kstat/zfs/dbgmsg
206 	 *
207 	 * To clear the buffer:
208 	 * $ echo 0 > /proc/spl/kstat/zfs/dbgmsg
209 	 */
210 	__zfs_dbgmsg(buf);
211 
212 	kmem_free(buf, size);
213 }
214 
215 module_param(zfs_dbgmsg_enable, int, 0644);
216 MODULE_PARM_DESC(zfs_dbgmsg_enable, "Enable ZFS debug message log");
217 
218 module_param(zfs_dbgmsg_maxsize, uint, 0644);
219 MODULE_PARM_DESC(zfs_dbgmsg_maxsize, "Maximum ZFS debug log size");
220