]>
Commit | Line | Data |
---|---|---|
f4b37741 | 1 | #ifndef _SPL_DEBUG_H |
2 | #define _SPL_DEBUG_H | |
3 | ||
57d1b188 | 4 | #include <linux/sched.h> /* THREAD_SIZE */ |
5 | #include <linux/proc_fs.h> | |
6 | ||
8d0f1ee9 | 7 | extern unsigned long spl_debug_mask; |
8 | extern unsigned long spl_debug_subsys; | |
9 | ||
57d1b188 | 10 | #define S_UNDEFINED 0x00000001 |
11 | #define S_ATOMIC 0x00000002 | |
12 | #define S_KOBJ 0x00000004 | |
13 | #define S_VNODE 0x00000008 | |
14 | #define S_TIME 0x00000010 | |
15 | #define S_RWLOCK 0x00000020 | |
16 | #define S_THREAD 0x00000040 | |
17 | #define S_CONDVAR 0x00000080 | |
18 | #define S_MUTEX 0x00000100 | |
19 | #define S_RNG 0x00000200 | |
20 | #define S_TASKQ 0x00000400 | |
21 | #define S_KMEM 0x00000800 | |
22 | #define S_DEBUG 0x00001000 | |
23 | #define S_GENERIC 0x00002000 | |
24 | #define S_PROC 0x00004000 | |
937879f1 | 25 | #define S_MODULE 0x00008000 |
57d1b188 | 26 | |
27 | #define D_TRACE 0x00000001 | |
28 | #define D_INFO 0x00000002 | |
29 | #define D_WARNING 0x00000004 | |
30 | #define D_ERROR 0x00000008 | |
31 | #define D_EMERG 0x00000010 | |
32 | #define D_CONSOLE 0x00000020 | |
33 | #define D_IOCTL 0x00000040 | |
34 | #define D_DPRINTF 0x00000080 | |
35 | #define D_OTHER 0x00000100 | |
36 | ||
37 | #define D_CANTMASK (D_ERROR | D_EMERG | D_WARNING | D_CONSOLE) | |
38 | #define DEBUG_SUBSYSTEM S_UNDEFINED | |
39 | ||
40 | int debug_init(void); | |
41 | void debug_fini(void); | |
42 | int spl_debug_mask2str(char *str, int size, unsigned long mask, int is_subsys); | |
43 | int spl_debug_str2mask(unsigned long *mask, const char *str, int is_subsys); | |
44 | ||
45 | extern unsigned long spl_debug_subsys; | |
46 | extern unsigned long spl_debug_mask; | |
47 | extern unsigned long spl_debug_printk; | |
48 | extern int spl_debug_mb; | |
49 | extern unsigned int spl_debug_binary; | |
50 | extern unsigned int spl_debug_catastrophe; | |
51 | extern unsigned int spl_debug_panic_on_bug; | |
52 | extern char spl_debug_file_path[PATH_MAX]; | |
53 | extern unsigned int spl_console_ratelimit; | |
54 | extern long spl_console_max_delay; | |
55 | extern long spl_console_min_delay; | |
56 | extern unsigned int spl_console_backoff; | |
57 | extern unsigned int spl_debug_stack; | |
58 | ||
b831734a | 59 | #define TCD_MAX_PAGES (5 << (20 - PAGE_SHIFT)) |
60 | #define TCD_STOCK_PAGES (TCD_MAX_PAGES) | |
61 | #define TRACE_CONSOLE_BUFFER_SIZE 1024 | |
57d1b188 | 62 | |
b831734a | 63 | #define SPL_DEFAULT_MAX_DELAY (600 * HZ) |
64 | #define SPL_DEFAULT_MIN_DELAY ((HZ + 1) / 2) | |
65 | #define SPL_DEFAULT_BACKOFF 2 | |
57d1b188 | 66 | |
7fea96c0 | 67 | #define DL_NOTHREAD 0x0001 /* Do not create a new thread */ |
b831734a | 68 | #define DL_SINGLE_CPU 0x0002 /* Collect pages from this CPU */ |
7fea96c0 | 69 | |
70 | typedef struct dumplog_priv { | |
71 | wait_queue_head_t dp_waitq; | |
72 | pid_t dp_pid; | |
73 | int dp_flags; | |
74 | atomic_t dp_done; | |
75 | } dumplog_priv_t; | |
76 | ||
57d1b188 | 77 | typedef struct { |
78 | unsigned long cdls_next; | |
79 | int cdls_count; | |
80 | long cdls_delay; | |
81 | } spl_debug_limit_state_t; | |
82 | ||
83 | /* Three trace data types */ | |
84 | typedef enum { | |
85 | TCD_TYPE_PROC, | |
86 | TCD_TYPE_SOFTIRQ, | |
87 | TCD_TYPE_IRQ, | |
88 | TCD_TYPE_MAX | |
89 | } tcd_type_t; | |
90 | ||
91 | union trace_data_union { | |
92 | struct trace_cpu_data { | |
93 | /* pages with trace records not yet processed by tracefiled */ | |
94 | struct list_head tcd_pages; | |
95 | /* number of pages on ->tcd_pages */ | |
96 | unsigned long tcd_cur_pages; | |
97 | /* Max number of pages allowed on ->tcd_pages */ | |
98 | unsigned long tcd_max_pages; | |
99 | ||
100 | /* | |
101 | * preallocated pages to write trace records into. Pages from | |
102 | * ->tcd_stock_pages are moved to ->tcd_pages by spl_debug_msg(). | |
103 | * | |
104 | * This list is necessary, because on some platforms it's | |
105 | * impossible to perform efficient atomic page allocation in a | |
106 | * non-blockable context. | |
107 | * | |
108 | * Such platforms fill ->tcd_stock_pages "on occasion", when | |
109 | * tracing code is entered in blockable context. | |
110 | * | |
111 | * trace_get_tage_try() tries to get a page from | |
112 | * ->tcd_stock_pages first and resorts to atomic page | |
113 | * allocation only if this queue is empty. ->tcd_stock_pages | |
114 | * is replenished when tracing code is entered in blocking | |
115 | * context (darwin-tracefile.c:trace_get_tcd()). We try to | |
116 | * maintain TCD_STOCK_PAGES (40 by default) pages in this | |
117 | * queue. Atomic allocation is only required if more than | |
118 | * TCD_STOCK_PAGES pagesful are consumed by trace records all | |
119 | * emitted in non-blocking contexts. Which is quite unlikely. | |
120 | */ | |
121 | struct list_head tcd_stock_pages; | |
122 | /* number of pages on ->tcd_stock_pages */ | |
123 | unsigned long tcd_cur_stock_pages; | |
124 | ||
125 | unsigned short tcd_shutting_down; | |
126 | unsigned short tcd_cpu; | |
127 | unsigned short tcd_type; | |
128 | /* The factors to share debug memory. */ | |
129 | unsigned short tcd_pages_factor; | |
130 | } tcd; | |
131 | char __pad[L1_CACHE_ALIGN(sizeof(struct trace_cpu_data))]; | |
132 | }; | |
133 | ||
134 | extern union trace_data_union (*trace_data[TCD_TYPE_MAX])[NR_CPUS]; | |
135 | ||
136 | #define tcd_for_each(tcd, i, j) \ | |
137 | for (i = 0; trace_data[i] != NULL; i++) \ | |
138 | for (j = 0, ((tcd) = &(*trace_data[i])[j].tcd); \ | |
139 | j < num_possible_cpus(); j++, (tcd) = &(*trace_data[i])[j].tcd) | |
140 | ||
141 | #define tcd_for_each_type_lock(tcd, i) \ | |
142 | for (i = 0; trace_data[i] && \ | |
143 | (tcd = &(*trace_data[i])[smp_processor_id()].tcd) && \ | |
144 | trace_lock_tcd(tcd); trace_unlock_tcd(tcd), i++) | |
145 | ||
146 | struct trace_page { | |
147 | struct page * page; /* page itself */ | |
148 | struct list_head linkage; /* Used by lists in trace_data_union */ | |
149 | unsigned int used; /* number of bytes used within this page */ | |
150 | unsigned short cpu; /* cpu that owns this page */ | |
151 | unsigned short type; /* type(context) of this page */ | |
152 | }; | |
153 | ||
154 | struct page_collection { | |
155 | struct list_head pc_pages; | |
156 | spinlock_t pc_lock; | |
157 | int pc_want_daemon_pages; | |
158 | }; | |
159 | ||
b831734a | 160 | #define SBUG() spl_debug_bug(__FILE__, __FUNCTION__, __LINE__, 0); |
2fae1b3d | 161 | |
937879f1 | 162 | #ifdef __ia64__ |
163 | #define CDEBUG_STACK() (THREAD_SIZE - \ | |
164 | ((unsigned long)__builtin_dwarf_cfa() & \ | |
165 | (THREAD_SIZE - 1))) | |
166 | #else | |
167 | #define CDEBUG_STACK() (THREAD_SIZE - \ | |
168 | ((unsigned long)__builtin_frame_address(0) & \ | |
169 | (THREAD_SIZE - 1))) | |
170 | # endif /* __ia64__ */ | |
171 | ||
b831734a | 172 | /* DL_SINGLE_CPU flag is passed to spl_debug_bug() because we are about |
173 | * to over run our stack and likely damage at least one other unknown | |
174 | * thread stack. We must finish generating the needed debug info within | |
175 | * this thread context because once we yeild the CPU its very likely | |
176 | * the system will crash. | |
7fea96c0 | 177 | */ |
937879f1 | 178 | #define __CHECK_STACK(file, func, line) \ |
179 | do { \ | |
b831734a | 180 | if (unlikely(CDEBUG_STACK() > spl_debug_stack)) { \ |
181 | spl_debug_stack = CDEBUG_STACK(); \ | |
937879f1 | 182 | \ |
b831734a | 183 | if (unlikely(CDEBUG_STACK() > (4 * THREAD_SIZE) / 5)) { \ |
184 | spl_debug_msg(NULL, D_TRACE, D_WARNING, \ | |
185 | file, func, line, "Error " \ | |
186 | "exceeded maximum safe stack " \ | |
187 | "size (%lu/%lu)\n", \ | |
188 | CDEBUG_STACK(), THREAD_SIZE); \ | |
189 | spl_debug_bug(file, func, line, DL_SINGLE_CPU); \ | |
190 | } \ | |
937879f1 | 191 | } \ |
192 | } while (0) | |
193 | ||
892d5106 | 194 | #define CHECK_STACK() __CHECK_STACK(__FILE__, __func__, __LINE__) |
937879f1 | 195 | |
57d1b188 | 196 | /* ASSERTION that is safe to use within the debug system */ |
b831734a | 197 | #define __ASSERT(cond) \ |
198 | do { \ | |
199 | if (unlikely(!(cond))) { \ | |
200 | printk(KERN_ERR "ASSERTION(" #cond ") failed"); \ | |
6e605b6e | 201 | BUG(); \ |
b831734a | 202 | } \ |
57d1b188 | 203 | } while (0) |
204 | ||
b831734a | 205 | #define __ASSERT_TAGE_INVARIANT(tage) \ |
206 | do { \ | |
207 | __ASSERT(tage != NULL); \ | |
208 | __ASSERT(tage->page != NULL); \ | |
209 | __ASSERT(tage->used <= PAGE_SIZE); \ | |
210 | __ASSERT(page_count(tage->page) > 0); \ | |
57d1b188 | 211 | } while(0) |
212 | ||
213 | /* ASSERTION that will debug log used outside the debug sysytem */ | |
214 | #define ASSERT(cond) \ | |
215 | do { \ | |
b831734a | 216 | CHECK_STACK(); \ |
217 | \ | |
57d1b188 | 218 | if (unlikely(!(cond))) { \ |
219 | spl_debug_msg(NULL, DEBUG_SUBSYSTEM, D_EMERG, \ | |
220 | __FILE__, __FUNCTION__, __LINE__, \ | |
221 | "ASSERTION(" #cond ") failed\n"); \ | |
b831734a | 222 | SBUG(); \ |
223 | } \ | |
57d1b188 | 224 | } while (0) |
225 | ||
226 | #define ASSERTF(cond, fmt, a...) \ | |
227 | do { \ | |
b831734a | 228 | CHECK_STACK(); \ |
229 | \ | |
57d1b188 | 230 | if (unlikely(!(cond))) { \ |
231 | spl_debug_msg(NULL, DEBUG_SUBSYSTEM, D_EMERG, \ | |
232 | __FILE__, __FUNCTION__, __LINE__, \ | |
233 | "ASSERTION(" #cond ") failed:" fmt, \ | |
234 | ## a); \ | |
b831734a | 235 | SBUG(); \ |
57d1b188 | 236 | } \ |
237 | } while (0) | |
238 | ||
239 | #define VERIFY3_IMPL(LEFT, OP, RIGHT, TYPE, FMT, CAST) \ | |
240 | do { \ | |
b831734a | 241 | CHECK_STACK(); \ |
242 | \ | |
243 | if (!((TYPE)(LEFT) OP (TYPE)(RIGHT))) { \ | |
57d1b188 | 244 | spl_debug_msg(NULL, DEBUG_SUBSYSTEM, D_EMERG, \ |
245 | __FILE__, __FUNCTION__, __LINE__, \ | |
246 | "VERIFY3(" FMT " " #OP " " FMT ")\n", \ | |
b831734a | 247 | CAST (LEFT), CAST (RIGHT)); \ |
248 | SBUG(); \ | |
57d1b188 | 249 | } \ |
250 | } while (0) | |
251 | ||
252 | #define VERIFY3S(x,y,z) VERIFY3_IMPL(x, y, z, int64_t, "%ld", (long)) | |
253 | #define VERIFY3U(x,y,z) VERIFY3_IMPL(x, y, z, uint64_t, "%lu", (unsigned long)) | |
254 | #define VERIFY3P(x,y,z) VERIFY3_IMPL(x, y, z, uintptr_t, "%p", (void *)) | |
255 | ||
256 | #define ASSERT3S(x,y,z) VERIFY3S(x, y, z) | |
257 | #define ASSERT3U(x,y,z) VERIFY3U(x, y, z) | |
258 | #define ASSERT3P(x,y,z) VERIFY3P(x, y, z) | |
259 | ||
b831734a | 260 | #define VERIFY(x) ASSERT(x) |
57d1b188 | 261 | |
262 | #define spl_debug_msg(cdls, subsys, mask, file, fn, line, format, a...) \ | |
263 | spl_debug_vmsg(cdls, subsys, mask, file, fn, \ | |
264 | line, NULL, NULL, format, ##a) | |
265 | ||
57d1b188 | 266 | #define __CDEBUG(cdls, subsys, mask, format, a...) \ |
267 | do { \ | |
268 | CHECK_STACK(); \ | |
269 | \ | |
270 | if (((mask) & D_CANTMASK) != 0 || \ | |
271 | ((spl_debug_mask & (mask)) != 0 && \ | |
272 | (spl_debug_subsys & (subsys)) != 0)) \ | |
273 | spl_debug_msg(cdls, subsys, mask, \ | |
274 | __FILE__, __FUNCTION__, __LINE__, \ | |
275 | format, ## a); \ | |
276 | } while (0) | |
277 | ||
278 | #define CDEBUG(mask, format, a...) \ | |
279 | __CDEBUG(NULL, DEBUG_SUBSYSTEM, mask, format, ## a) | |
280 | ||
281 | #define __CDEBUG_LIMIT(subsys, mask, format, a...) \ | |
282 | do { \ | |
283 | static spl_debug_limit_state_t cdls; \ | |
284 | \ | |
285 | __CDEBUG(&cdls, subsys, mask, format, ## a); \ | |
286 | } while (0) | |
287 | ||
288 | #define CDEBUG_LIMIT(mask, format, a...) \ | |
289 | __CDEBUG_LIMIT(DEBUG_SUBSYSTEM, mask, format, ## a) | |
290 | ||
57d1b188 | 291 | #define CWARN(fmt, a...) CDEBUG_LIMIT(D_WARNING, fmt, ## a) |
292 | #define CERROR(fmt, a...) CDEBUG_LIMIT(D_ERROR, fmt, ## a) | |
293 | #define CEMERG(fmt, a...) CDEBUG_LIMIT(D_EMERG, fmt, ## a) | |
294 | #define CONSOLE(mask, fmt, a...) CDEBUG(D_CONSOLE | (mask), fmt, ## a) | |
295 | ||
296 | #define GOTO(label, rc) \ | |
297 | do { \ | |
298 | long GOTO__ret = (long)(rc); \ | |
299 | CDEBUG(D_TRACE,"Process leaving via %s (rc=%lu : %ld : %lx)\n", \ | |
300 | #label, (unsigned long)GOTO__ret, (signed long)GOTO__ret,\ | |
301 | (signed long)GOTO__ret); \ | |
302 | goto label; \ | |
303 | } while (0) | |
304 | ||
305 | #define RETURN(rc) \ | |
306 | do { \ | |
307 | typeof(rc) RETURN__ret = (rc); \ | |
308 | CDEBUG(D_TRACE, "Process leaving (rc=%lu : %ld : %lx)\n", \ | |
309 | (long)RETURN__ret, (long)RETURN__ret, (long)RETURN__ret);\ | |
310 | return RETURN__ret; \ | |
311 | } while (0) | |
312 | ||
313 | #define ENTRY \ | |
314 | do { \ | |
315 | CDEBUG(D_TRACE, "Process entered\n"); \ | |
316 | } while (0) | |
317 | ||
318 | #define EXIT \ | |
319 | do { \ | |
320 | CDEBUG(D_TRACE, "Process leaving\n"); \ | |
321 | } while(0) | |
322 | ||
323 | extern int spl_debug_vmsg(spl_debug_limit_state_t *cdls, int subsys, int mask, | |
b831734a | 324 | const char *file, const char *fn, const int line, |
325 | const char *format1, va_list args, const char *format2, ...); | |
57d1b188 | 326 | |
327 | extern unsigned long spl_debug_set_mask(unsigned long mask); | |
328 | extern unsigned long spl_debug_get_mask(void); | |
329 | extern unsigned long spl_debug_set_subsys(unsigned long mask); | |
330 | extern unsigned long spl_debug_get_subsys(void); | |
331 | extern int spl_debug_set_mb(int mb); | |
332 | extern int spl_debug_get_mb(void); | |
333 | ||
7fea96c0 | 334 | extern int spl_debug_dumplog(int flags); |
57d1b188 | 335 | extern void spl_debug_dumpstack(struct task_struct *tsk); |
7fea96c0 | 336 | extern void spl_debug_bug(char *file, const char *func, const int line, int flags); |
57d1b188 | 337 | |
338 | extern int spl_debug_clear_buffer(void); | |
339 | extern int spl_debug_mark_buffer(char *text); | |
8d0f1ee9 | 340 | |
f4b37741 | 341 | #endif /* SPL_DEBUG_H */ |