xref: /freebsd-src/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_debug.c (revision 7a7741af18d6c8a804cc643cb7ecda9d730c6aa6)
1eda14cbcSMatt Macy /*
2eda14cbcSMatt Macy  * CDDL HEADER START
3eda14cbcSMatt Macy  *
4eda14cbcSMatt Macy  * The contents of this file are subject to the terms of the
5eda14cbcSMatt Macy  * Common Development and Distribution License (the "License").
6eda14cbcSMatt Macy  * You may not use this file except in compliance with the License.
7eda14cbcSMatt Macy  *
8eda14cbcSMatt Macy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
10eda14cbcSMatt Macy  * See the License for the specific language governing permissions
11eda14cbcSMatt Macy  * and limitations under the License.
12eda14cbcSMatt Macy  *
13eda14cbcSMatt Macy  * When distributing Covered Code, include this CDDL HEADER in each
14eda14cbcSMatt Macy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15eda14cbcSMatt Macy  * If applicable, add the following below this CDDL HEADER, with the
16eda14cbcSMatt Macy  * fields enclosed by brackets "[]" replaced with your own identifying
17eda14cbcSMatt Macy  * information: Portions Copyright [yyyy] [name of copyright owner]
18eda14cbcSMatt Macy  *
19eda14cbcSMatt Macy  * CDDL HEADER END
20eda14cbcSMatt Macy  */
21eda14cbcSMatt Macy /*
22eda14cbcSMatt Macy  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23eda14cbcSMatt Macy  * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
24eda14cbcSMatt Macy  */
25eda14cbcSMatt Macy 
26eda14cbcSMatt Macy #include <sys/zfs_context.h>
27eda14cbcSMatt Macy #include <sys/kstat.h>
28eda14cbcSMatt Macy 
29eda14cbcSMatt Macy typedef struct zfs_dbgmsg {
30eda14cbcSMatt Macy 	list_node_t zdm_node;
31eda14cbcSMatt Macy 	time_t zdm_timestamp;
32be181ee2SMartin Matuska 	uint_t zdm_size;
3315f0b8c3SMartin Matuska 	char zdm_msg[];
34eda14cbcSMatt Macy } zfs_dbgmsg_t;
35eda14cbcSMatt Macy 
36e92ffd9bSMartin Matuska static list_t zfs_dbgmsgs;
37be181ee2SMartin Matuska static uint_t zfs_dbgmsg_size = 0;
38e92ffd9bSMartin Matuska static kmutex_t zfs_dbgmsgs_lock;
39be181ee2SMartin Matuska uint_t zfs_dbgmsg_maxsize = 4<<20; /* 4MB */
40e92ffd9bSMartin Matuska static kstat_t *zfs_dbgmsg_kstat;
41eda14cbcSMatt Macy 
42eda14cbcSMatt Macy /*
43eda14cbcSMatt Macy  * Internal ZFS debug messages are enabled by default.
44eda14cbcSMatt Macy  *
4516038816SMartin Matuska  * # Print debug messages as they're logged
46eda14cbcSMatt Macy  * dtrace -n 'zfs-dbgmsg { print(stringof(arg0)); }'
47eda14cbcSMatt Macy  *
4816038816SMartin Matuska  * # Print all logged dbgmsg entries
4916038816SMartin Matuska  * sysctl kstat.zfs.misc.dbgmsg
5016038816SMartin Matuska  *
51eda14cbcSMatt Macy  * # Disable the kernel debug message log.
52eda14cbcSMatt Macy  * sysctl vfs.zfs.dbgmsg_enable=0
53eda14cbcSMatt Macy  */
54e92ffd9bSMartin Matuska int zfs_dbgmsg_enable = B_TRUE;
55eda14cbcSMatt Macy 
56eda14cbcSMatt Macy static int
57eda14cbcSMatt Macy zfs_dbgmsg_headers(char *buf, size_t size)
58eda14cbcSMatt Macy {
59eda14cbcSMatt Macy 	(void) snprintf(buf, size, "%-12s %-8s\n", "timestamp", "message");
60eda14cbcSMatt Macy 
61eda14cbcSMatt Macy 	return (0);
62eda14cbcSMatt Macy }
63eda14cbcSMatt Macy 
64eda14cbcSMatt Macy static int
65eda14cbcSMatt Macy zfs_dbgmsg_data(char *buf, size_t size, void *data)
66eda14cbcSMatt Macy {
67eda14cbcSMatt Macy 	zfs_dbgmsg_t *zdm = (zfs_dbgmsg_t *)data;
68eda14cbcSMatt Macy 
69eda14cbcSMatt Macy 	(void) snprintf(buf, size, "%-12llu %-s\n",
70eda14cbcSMatt Macy 	    (u_longlong_t)zdm->zdm_timestamp, zdm->zdm_msg);
71eda14cbcSMatt Macy 
72eda14cbcSMatt Macy 	return (0);
73eda14cbcSMatt Macy }
74eda14cbcSMatt Macy 
75eda14cbcSMatt Macy static void *
76eda14cbcSMatt Macy zfs_dbgmsg_addr(kstat_t *ksp, loff_t n)
77eda14cbcSMatt Macy {
78eda14cbcSMatt Macy 	zfs_dbgmsg_t *zdm = (zfs_dbgmsg_t *)ksp->ks_private;
79eda14cbcSMatt Macy 
80eda14cbcSMatt Macy 	ASSERT(MUTEX_HELD(&zfs_dbgmsgs_lock));
81eda14cbcSMatt Macy 
82eda14cbcSMatt Macy 	if (n == 0)
83eda14cbcSMatt Macy 		ksp->ks_private = list_head(&zfs_dbgmsgs);
84eda14cbcSMatt Macy 	else if (zdm)
85eda14cbcSMatt Macy 		ksp->ks_private = list_next(&zfs_dbgmsgs, zdm);
86eda14cbcSMatt Macy 
87eda14cbcSMatt Macy 	return (ksp->ks_private);
88eda14cbcSMatt Macy }
89eda14cbcSMatt Macy 
90eda14cbcSMatt Macy static void
91be181ee2SMartin Matuska zfs_dbgmsg_purge(uint_t max_size)
92eda14cbcSMatt Macy {
93eda14cbcSMatt Macy 	zfs_dbgmsg_t *zdm;
94be181ee2SMartin Matuska 	uint_t size;
95eda14cbcSMatt Macy 
96eda14cbcSMatt Macy 	ASSERT(MUTEX_HELD(&zfs_dbgmsgs_lock));
97eda14cbcSMatt Macy 
98eda14cbcSMatt Macy 	while (zfs_dbgmsg_size > max_size) {
99eda14cbcSMatt Macy 		zdm = list_remove_head(&zfs_dbgmsgs);
100eda14cbcSMatt Macy 		if (zdm == NULL)
101eda14cbcSMatt Macy 			return;
102eda14cbcSMatt Macy 
103eda14cbcSMatt Macy 		size = zdm->zdm_size;
104eda14cbcSMatt Macy 		kmem_free(zdm, size);
105eda14cbcSMatt Macy 		zfs_dbgmsg_size -= size;
106eda14cbcSMatt Macy 	}
107eda14cbcSMatt Macy }
108eda14cbcSMatt Macy 
109eda14cbcSMatt Macy static int
110eda14cbcSMatt Macy zfs_dbgmsg_update(kstat_t *ksp, int rw)
111eda14cbcSMatt Macy {
112eda14cbcSMatt Macy 	if (rw == KSTAT_WRITE)
113eda14cbcSMatt Macy 		zfs_dbgmsg_purge(0);
114eda14cbcSMatt Macy 
115eda14cbcSMatt Macy 	return (0);
116eda14cbcSMatt Macy }
117eda14cbcSMatt Macy 
118eda14cbcSMatt Macy void
119eda14cbcSMatt Macy zfs_dbgmsg_init(void)
120eda14cbcSMatt Macy {
121eda14cbcSMatt Macy 	list_create(&zfs_dbgmsgs, sizeof (zfs_dbgmsg_t),
122eda14cbcSMatt Macy 	    offsetof(zfs_dbgmsg_t, zdm_node));
123eda14cbcSMatt Macy 	mutex_init(&zfs_dbgmsgs_lock, NULL, MUTEX_DEFAULT, NULL);
124eda14cbcSMatt Macy 
125eda14cbcSMatt Macy 	zfs_dbgmsg_kstat = kstat_create("zfs", 0, "dbgmsg", "misc",
126eda14cbcSMatt Macy 	    KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
127eda14cbcSMatt Macy 	if (zfs_dbgmsg_kstat) {
128eda14cbcSMatt Macy 		zfs_dbgmsg_kstat->ks_lock = &zfs_dbgmsgs_lock;
129eda14cbcSMatt Macy 		zfs_dbgmsg_kstat->ks_ndata = UINT32_MAX;
130eda14cbcSMatt Macy 		zfs_dbgmsg_kstat->ks_private = NULL;
131eda14cbcSMatt Macy 		zfs_dbgmsg_kstat->ks_update = zfs_dbgmsg_update;
132eda14cbcSMatt Macy 		kstat_set_raw_ops(zfs_dbgmsg_kstat, zfs_dbgmsg_headers,
133eda14cbcSMatt Macy 		    zfs_dbgmsg_data, zfs_dbgmsg_addr);
134eda14cbcSMatt Macy 		kstat_install(zfs_dbgmsg_kstat);
135eda14cbcSMatt Macy 	}
136eda14cbcSMatt Macy }
137eda14cbcSMatt Macy 
138eda14cbcSMatt Macy void
139eda14cbcSMatt Macy zfs_dbgmsg_fini(void)
140eda14cbcSMatt Macy {
141eda14cbcSMatt Macy 	if (zfs_dbgmsg_kstat)
142eda14cbcSMatt Macy 		kstat_delete(zfs_dbgmsg_kstat);
143*7a7741afSMartin Matuska 
144eda14cbcSMatt Macy 	mutex_enter(&zfs_dbgmsgs_lock);
145eda14cbcSMatt Macy 	zfs_dbgmsg_purge(0);
146eda14cbcSMatt Macy 	mutex_exit(&zfs_dbgmsgs_lock);
147eda14cbcSMatt Macy 	mutex_destroy(&zfs_dbgmsgs_lock);
148eda14cbcSMatt Macy }
149eda14cbcSMatt Macy 
150eda14cbcSMatt Macy void
151eda14cbcSMatt Macy __zfs_dbgmsg(char *buf)
152eda14cbcSMatt Macy {
153eda14cbcSMatt Macy 	zfs_dbgmsg_t *zdm;
154be181ee2SMartin Matuska 	uint_t size;
155eda14cbcSMatt Macy 
156eda14cbcSMatt Macy 	DTRACE_PROBE1(zfs__dbgmsg, char *, buf);
157eda14cbcSMatt Macy 
15815f0b8c3SMartin Matuska 	size = sizeof (zfs_dbgmsg_t) + strlen(buf) + 1;
159eda14cbcSMatt Macy 	zdm = kmem_zalloc(size, KM_SLEEP);
160eda14cbcSMatt Macy 	zdm->zdm_size = size;
161eda14cbcSMatt Macy 	zdm->zdm_timestamp = gethrestime_sec();
162eda14cbcSMatt Macy 	strcpy(zdm->zdm_msg, buf);
163eda14cbcSMatt Macy 
164eda14cbcSMatt Macy 	mutex_enter(&zfs_dbgmsgs_lock);
165eda14cbcSMatt Macy 	list_insert_tail(&zfs_dbgmsgs, zdm);
166eda14cbcSMatt Macy 	zfs_dbgmsg_size += size;
167be181ee2SMartin Matuska 	zfs_dbgmsg_purge(zfs_dbgmsg_maxsize);
168eda14cbcSMatt Macy 	mutex_exit(&zfs_dbgmsgs_lock);
169eda14cbcSMatt Macy }
170eda14cbcSMatt Macy 
171eda14cbcSMatt Macy void
172eda14cbcSMatt Macy __set_error(const char *file, const char *func, int line, int err)
173eda14cbcSMatt Macy {
174eda14cbcSMatt Macy 	/*
175eda14cbcSMatt Macy 	 * To enable this:
176eda14cbcSMatt Macy 	 *
177eda14cbcSMatt Macy 	 * $ echo 512 >/sys/module/zfs/parameters/zfs_flags
178eda14cbcSMatt Macy 	 */
179eda14cbcSMatt Macy 	if (zfs_flags & ZFS_DEBUG_SET_ERROR)
18033b8c039SMartin Matuska 		__dprintf(B_FALSE, file, func, line, "error %lu", (ulong_t)err);
181eda14cbcSMatt Macy }
182eda14cbcSMatt Macy 
183eda14cbcSMatt Macy void
184eda14cbcSMatt Macy __dprintf(boolean_t dprint, const char *file, const char *func,
185eda14cbcSMatt Macy     int line, const char *fmt, ...)
186eda14cbcSMatt Macy {
187eda14cbcSMatt Macy 	const char *newfile;
188eda14cbcSMatt Macy 	va_list adx;
189eda14cbcSMatt Macy 	size_t size;
190eda14cbcSMatt Macy 	char *buf;
191eda14cbcSMatt Macy 	char *nl;
192eda14cbcSMatt Macy 	int i;
193eda14cbcSMatt Macy 
194eda14cbcSMatt Macy 	size = 1024;
195eda14cbcSMatt Macy 	buf = kmem_alloc(size, KM_SLEEP);
196eda14cbcSMatt Macy 
197eda14cbcSMatt Macy 	/*
198eda14cbcSMatt Macy 	 * Get rid of annoying prefix to filename.
199eda14cbcSMatt Macy 	 */
200eda14cbcSMatt Macy 	newfile = strrchr(file, '/');
201eda14cbcSMatt Macy 	if (newfile != NULL) {
202eda14cbcSMatt Macy 		newfile = newfile + 1; /* Get rid of leading / */
203eda14cbcSMatt Macy 	} else {
204eda14cbcSMatt Macy 		newfile = file;
205eda14cbcSMatt Macy 	}
206eda14cbcSMatt Macy 
207eda14cbcSMatt Macy 	i = snprintf(buf, size, "%s:%d:%s(): ", newfile, line, func);
208eda14cbcSMatt Macy 
209eda14cbcSMatt Macy 	if (i < size) {
210eda14cbcSMatt Macy 		va_start(adx, fmt);
211eda14cbcSMatt Macy 		(void) vsnprintf(buf + i, size - i, fmt, adx);
212eda14cbcSMatt Macy 		va_end(adx);
213eda14cbcSMatt Macy 	}
214eda14cbcSMatt Macy 
215eda14cbcSMatt Macy 	/*
216*7a7741afSMartin Matuska 	 * Get rid of trailing newline for dprintf logs.
217eda14cbcSMatt Macy 	 */
218*7a7741afSMartin Matuska 	if (dprint && buf[0] != '\0') {
219*7a7741afSMartin Matuska 		nl = &buf[strlen(buf) - 1];
220*7a7741afSMartin Matuska 		if (*nl == '\n')
221eda14cbcSMatt Macy 			*nl = '\0';
222*7a7741afSMartin Matuska 	}
223eda14cbcSMatt Macy 
224*7a7741afSMartin Matuska 	/*
225*7a7741afSMartin Matuska 	 * To get this data:
226*7a7741afSMartin Matuska 	 *
227*7a7741afSMartin Matuska 	 * $ sysctl -n kstat.zfs.misc.dbgmsg
228*7a7741afSMartin Matuska 	 */
229eda14cbcSMatt Macy 	__zfs_dbgmsg(buf);
230eda14cbcSMatt Macy 
231eda14cbcSMatt Macy 	kmem_free(buf, size);
232eda14cbcSMatt Macy }
233eda14cbcSMatt Macy 
234eda14cbcSMatt Macy ZFS_MODULE_PARAM(zfs, zfs_, dbgmsg_enable, INT, ZMOD_RW,
235eda14cbcSMatt Macy 	"Enable ZFS debug message log");
236eda14cbcSMatt Macy 
237be181ee2SMartin Matuska ZFS_MODULE_PARAM(zfs, zfs_, dbgmsg_maxsize, UINT, ZMOD_RW,
238eda14cbcSMatt Macy 	"Maximum ZFS debug log size");
239