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