]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From jbaron@redhat.com Tue Aug 12 17:09:39 2008 |
2 | From: Jason Baron <jbaron@redhat.com> | |
3 | Date: Tue, 12 Aug 2008 16:46:19 -0400 | |
4 | Subject: driver core: basic infrastructure for per-module dynamic debug messages | |
5 | To: Greg KH <greg@kroah.com> | |
6 | Cc: Randy Dunlap <randy.dunlap@oracle.com>, linux-kernel@vger.kernel.org, akpm@linux-foundation.org, joe@perches.com, nick@nick-andrew.net | |
7 | Message-ID: <20080812204619.GE6056@redhat.com> | |
8 | Patch-mainline: 2.6.28 | |
9 | ||
10 | Base infrastructure to enable per-module debug messages. | |
11 | ||
12 | I've introduced CONFIG_DYNAMIC_PRINTK_DEBUG, which when enabled centralizes | |
13 | control of debugging statements on a per-module basis in one /proc file, | |
14 | currently, <debugfs>/dynamic_printk/modules. When, CONFIG_DYNAMIC_PRINTK_DEBUG, | |
15 | is not set, debugging statements can still be enabled as before, often by | |
16 | defining 'DEBUG' for the proper compilation unit. Thus, this patch set has no | |
17 | affect when CONFIG_DYNAMIC_PRINTK_DEBUG is not set. | |
18 | ||
19 | The infrastructure currently ties into all pr_debug() and dev_dbg() calls. That | |
20 | is, if CONFIG_DYNAMIC_PRINTK_DEBUG is set, all pr_debug() and dev_dbg() calls | |
21 | can be dynamically enabled/disabled on a per-module basis. | |
22 | ||
23 | Future plans include extending this functionality to subsystems, that define | |
24 | their own debug levels and flags. | |
25 | ||
26 | Usage: | |
27 | ||
28 | Dynamic debugging is controlled by the debugfs file, | |
29 | <debugfs>/dynamic_printk/modules. This file contains a list of the modules that | |
30 | can be enabled. The format of the file is as follows: | |
31 | ||
32 | <module_name> <enabled=0/1> | |
33 | . | |
34 | . | |
35 | . | |
36 | ||
37 | <module_name> : Name of the module in which the debug call resides | |
38 | <enabled=0/1> : whether the messages are enabled or not | |
39 | ||
40 | For example: | |
41 | ||
42 | snd_hda_intel enabled=0 | |
43 | fixup enabled=1 | |
44 | driver enabled=0 | |
45 | ||
46 | Enable a module: | |
47 | ||
48 | $echo "set enabled=1 <module_name>" > dynamic_printk/modules | |
49 | ||
50 | Disable a module: | |
51 | ||
52 | $echo "set enabled=0 <module_name>" > dynamic_printk/modules | |
53 | ||
54 | Enable all modules: | |
55 | ||
56 | $echo "set enabled=1 all" > dynamic_printk/modules | |
57 | ||
58 | Disable all modules: | |
59 | ||
60 | $echo "set enabled=0 all" > dynamic_printk/modules | |
61 | ||
62 | Finally, passing "dynamic_printk" at the command line enables | |
63 | debugging for all modules. This mode can be turned off via the above | |
64 | disable command. | |
65 | ||
66 | [gkh: minor cleanups and tweaks to make the build work quietly] | |
67 | ||
68 | Signed-off-by: Jason Baron <jbaron@redhat.com> | |
69 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
70 | ||
71 | ||
72 | --- | |
73 | Documentation/kernel-parameters.txt | 5 | |
74 | include/asm-generic/vmlinux.lds.h | 10 | |
75 | include/linux/device.h | 6 | |
76 | include/linux/dynamic_printk.h | 93 ++++++++ | |
77 | include/linux/kernel.h | 7 | |
78 | include/linux/module.h | 1 | |
79 | kernel/module.c | 31 ++ | |
80 | lib/Kconfig.debug | 55 ++++ | |
81 | lib/Makefile | 2 | |
82 | lib/dynamic_printk.c | 418 ++++++++++++++++++++++++++++++++++++ | |
83 | net/netfilter/nf_conntrack_pptp.c | 2 | |
84 | scripts/Makefile.lib | 11 | |
85 | scripts/basic/Makefile | 2 | |
86 | scripts/basic/hash.c | 64 +++++ | |
87 | 14 files changed, 700 insertions(+), 7 deletions(-) | |
88 | ||
89 | --- a/Documentation/kernel-parameters.txt | |
90 | +++ b/Documentation/kernel-parameters.txt | |
91 | @@ -1735,6 +1735,11 @@ and is between 256 and 4096 characters. | |
92 | autoconfiguration. | |
93 | Ranges are in pairs (memory base and size). | |
94 | ||
95 | + dynamic_printk | |
96 | + Enables pr_debug()/dev_dbg() calls if | |
97 | + CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled. These can also | |
98 | + be switched on/off via <debugfs>/dynamic_printk/modules | |
99 | + | |
100 | print-fatal-signals= | |
101 | [KNL] debug: print fatal signals | |
102 | print-fatal-signals=1: print segfault info to | |
103 | --- a/include/asm-generic/vmlinux.lds.h | |
104 | +++ b/include/asm-generic/vmlinux.lds.h | |
105 | @@ -268,7 +268,15 @@ | |
106 | CPU_DISCARD(init.data) \ | |
107 | CPU_DISCARD(init.rodata) \ | |
108 | MEM_DISCARD(init.data) \ | |
109 | - MEM_DISCARD(init.rodata) | |
110 | + MEM_DISCARD(init.rodata) \ | |
111 | + /* implement dynamic printk debug */ \ | |
112 | + VMLINUX_SYMBOL(__start___verbose_strings) = .; \ | |
113 | + *(__verbose_strings) \ | |
114 | + VMLINUX_SYMBOL(__stop___verbose_strings) = .; \ | |
115 | + . = ALIGN(8); \ | |
116 | + VMLINUX_SYMBOL(__start___verbose) = .; \ | |
117 | + *(__verbose) \ | |
118 | + VMLINUX_SYMBOL(__stop___verbose) = .; | |
119 | ||
120 | #define INIT_TEXT \ | |
121 | *(.init.text) \ | |
122 | --- a/include/linux/device.h | |
123 | +++ b/include/linux/device.h | |
124 | @@ -553,7 +553,11 @@ int printk_dev_hash(const char *, const | |
125 | #define dev_info(dev, format, arg...) \ | |
126 | dev_printk_hash(KERN_INFO , dev , format , ## arg) | |
127 | ||
128 | -#ifdef DEBUG | |
129 | +#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG) | |
130 | +#define dev_dbg(dev, format, ...) do { \ | |
131 | + dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \ | |
132 | + } while (0) | |
133 | +#elif defined(DEBUG) | |
134 | #define dev_dbg(dev, format, arg...) \ | |
135 | dev_printk(KERN_DEBUG , dev , format , ## arg) | |
136 | #else | |
137 | --- /dev/null | |
138 | +++ b/include/linux/dynamic_printk.h | |
139 | @@ -0,0 +1,93 @@ | |
140 | +#ifndef _DYNAMIC_PRINTK_H | |
141 | +#define _DYNAMIC_PRINTK_H | |
142 | + | |
143 | +#define DYNAMIC_DEBUG_HASH_BITS 6 | |
144 | +#define DEBUG_HASH_TABLE_SIZE (1 << DYNAMIC_DEBUG_HASH_BITS) | |
145 | + | |
146 | +#define TYPE_BOOLEAN 1 | |
147 | + | |
148 | +#define DYNAMIC_ENABLED_ALL 0 | |
149 | +#define DYNAMIC_ENABLED_NONE 1 | |
150 | +#define DYNAMIC_ENABLED_SOME 2 | |
151 | + | |
152 | +extern int dynamic_enabled; | |
153 | + | |
154 | +/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which | |
155 | + * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They | |
156 | + * use independent hash functions, to reduce the chance of false positives. | |
157 | + */ | |
158 | +extern long long dynamic_printk_enabled; | |
159 | +extern long long dynamic_printk_enabled2; | |
160 | + | |
161 | +struct mod_debug { | |
162 | + char *modname; | |
163 | + char *logical_modname; | |
164 | + char *flag_names; | |
165 | + int type; | |
166 | + int hash; | |
167 | + int hash2; | |
168 | +} __attribute__((aligned(8))); | |
169 | + | |
170 | +int register_dynamic_debug_module(char *mod_name, int type, char *share_name, | |
171 | + char *flags, int hash, int hash2); | |
172 | + | |
173 | +#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG) | |
174 | +extern int unregister_dynamic_debug_module(char *mod_name); | |
175 | +extern int __dynamic_dbg_enabled_helper(char *modname, int type, | |
176 | + int value, int hash); | |
177 | + | |
178 | +#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ \ | |
179 | + int __ret = 0; \ | |
180 | + if (unlikely((dynamic_printk_enabled & (1LL << DEBUG_HASH)) && \ | |
181 | + (dynamic_printk_enabled2 & (1LL << DEBUG_HASH2)))) \ | |
182 | + __ret = __dynamic_dbg_enabled_helper(module, type, \ | |
183 | + value, hash);\ | |
184 | + __ret; }) | |
185 | + | |
186 | +#define dynamic_pr_debug(fmt, ...) do { \ | |
187 | + static char mod_name[] \ | |
188 | + __attribute__((section("__verbose_strings"))) \ | |
189 | + = KBUILD_MODNAME; \ | |
190 | + static struct mod_debug descriptor \ | |
191 | + __used \ | |
192 | + __attribute__((section("__verbose"), aligned(8))) = \ | |
193 | + { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\ | |
194 | + if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \ | |
195 | + 0, 0, DEBUG_HASH)) \ | |
196 | + printk(KERN_DEBUG KBUILD_MODNAME ":" fmt, \ | |
197 | + ##__VA_ARGS__); \ | |
198 | + } while (0) | |
199 | + | |
200 | +#define dynamic_dev_dbg(dev, format, ...) do { \ | |
201 | + static char mod_name[] \ | |
202 | + __attribute__((section("__verbose_strings"))) \ | |
203 | + = KBUILD_MODNAME; \ | |
204 | + static struct mod_debug descriptor \ | |
205 | + __used \ | |
206 | + __attribute__((section("__verbose"), aligned(8))) = \ | |
207 | + { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\ | |
208 | + if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \ | |
209 | + 0, 0, DEBUG_HASH)) \ | |
210 | + dev_printk(KERN_DEBUG, dev, \ | |
211 | + KBUILD_MODNAME ": " format, \ | |
212 | + ##__VA_ARGS__); \ | |
213 | + } while (0) | |
214 | + | |
215 | +#else | |
216 | + | |
217 | +static inline int unregister_dynamic_debug_module(const char *mod_name) | |
218 | +{ | |
219 | + return 0; | |
220 | +} | |
221 | +static inline int __dynamic_dbg_enabled_helper(char *modname, int type, | |
222 | + int value, int hash) | |
223 | +{ | |
224 | + return 0; | |
225 | +} | |
226 | + | |
227 | +#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ 0; }) | |
228 | +#define dynamic_pr_debug(fmt, ...) do { } while (0) | |
229 | +#define dynamic_dev_dbg(dev, format, ...) do { } while (0) | |
230 | +#endif | |
231 | + | |
232 | +#endif | |
233 | --- a/include/linux/kernel.h | |
234 | +++ b/include/linux/kernel.h | |
235 | @@ -16,6 +16,7 @@ | |
236 | #include <linux/log2.h> | |
237 | #include <linux/typecheck.h> | |
238 | #include <linux/ratelimit.h> | |
239 | +#include <linux/dynamic_printk.h> | |
240 | #include <asm/byteorder.h> | |
241 | #include <asm/bug.h> | |
242 | ||
243 | @@ -331,8 +332,12 @@ int printk_hash(const char *, const char | |
244 | #define pr_info(fmt, arg...) \ | |
245 | pr_printk_hash(KERN_INFO, fmt, ##arg) | |
246 | ||
247 | -#ifdef DEBUG | |
248 | /* If you are writing a driver, please use dev_dbg instead */ | |
249 | +#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG) | |
250 | +#define pr_debug(fmt, ...) do { \ | |
251 | + dynamic_pr_debug(fmt, ##__VA_ARGS__); \ | |
252 | + } while (0) | |
253 | +#elif defined(DEBUG) | |
254 | #define pr_debug(fmt, arg...) \ | |
255 | pr_printk(KERN_DEBUG, fmt, ##arg) | |
256 | #else | |
257 | --- a/include/linux/module.h | |
258 | +++ b/include/linux/module.h | |
259 | @@ -345,7 +345,6 @@ struct module | |
260 | /* Reference counts */ | |
261 | struct module_ref ref[NR_CPUS]; | |
262 | #endif | |
263 | - | |
264 | }; | |
265 | #ifndef MODULE_ARCH_INIT | |
266 | #define MODULE_ARCH_INIT {} | |
267 | --- a/kernel/module.c | |
268 | +++ b/kernel/module.c | |
269 | @@ -798,6 +798,7 @@ SYSCALL_DEFINE2(delete_module, const cha | |
270 | mutex_lock(&module_mutex); | |
271 | /* Store the name of the last unloaded module for diagnostic purposes */ | |
272 | strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module)); | |
273 | + unregister_dynamic_debug_module(mod->name); | |
274 | free_module(mod); | |
275 | ||
276 | out: | |
277 | @@ -1823,6 +1824,33 @@ static inline void add_kallsyms(struct m | |
278 | } | |
279 | #endif /* CONFIG_KALLSYMS */ | |
280 | ||
281 | +#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG | |
282 | +static void dynamic_printk_setup(Elf_Shdr *sechdrs, unsigned int verboseindex) | |
283 | +{ | |
284 | + struct mod_debug *debug_info; | |
285 | + unsigned long pos, end; | |
286 | + unsigned int num_verbose; | |
287 | + | |
288 | + pos = sechdrs[verboseindex].sh_addr; | |
289 | + num_verbose = sechdrs[verboseindex].sh_size / | |
290 | + sizeof(struct mod_debug); | |
291 | + end = pos + (num_verbose * sizeof(struct mod_debug)); | |
292 | + | |
293 | + for (; pos < end; pos += sizeof(struct mod_debug)) { | |
294 | + debug_info = (struct mod_debug *)pos; | |
295 | + register_dynamic_debug_module(debug_info->modname, | |
296 | + debug_info->type, debug_info->logical_modname, | |
297 | + debug_info->flag_names, debug_info->hash, | |
298 | + debug_info->hash2); | |
299 | + } | |
300 | +} | |
301 | +#else | |
302 | +static inline void dynamic_printk_setup(Elf_Shdr *sechdrs, | |
303 | + unsigned int verboseindex) | |
304 | +{ | |
305 | +} | |
306 | +#endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */ | |
307 | + | |
308 | static void *module_alloc_update_bounds(unsigned long size) | |
309 | { | |
310 | void *ret = module_alloc(size); | |
311 | @@ -1871,6 +1899,7 @@ static noinline struct module *load_modu | |
312 | #endif | |
313 | unsigned int markersindex; | |
314 | unsigned int markersstringsindex; | |
315 | + unsigned int verboseindex; | |
316 | struct module *mod; | |
317 | long err = 0; | |
318 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ | |
319 | @@ -2157,6 +2186,7 @@ static noinline struct module *load_modu | |
320 | markersindex = find_sec(hdr, sechdrs, secstrings, "__markers"); | |
321 | markersstringsindex = find_sec(hdr, sechdrs, secstrings, | |
322 | "__markers_strings"); | |
323 | + verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose"); | |
324 | ||
325 | /* Now do relocations. */ | |
326 | for (i = 1; i < hdr->e_shnum; i++) { | |
327 | @@ -2207,6 +2237,7 @@ static noinline struct module *load_modu | |
328 | marker_update_probe_range(mod->markers, | |
329 | mod->markers + mod->num_markers); | |
330 | #endif | |
331 | + dynamic_printk_setup(sechdrs, verboseindex); | |
332 | err = module_finalize(hdr, sechdrs, mod); | |
333 | if (err < 0) | |
334 | goto cleanup; | |
335 | --- /dev/null | |
336 | +++ b/lib/dynamic_printk.c | |
337 | @@ -0,0 +1,418 @@ | |
338 | +/* | |
339 | + * lib/dynamic_printk.c | |
340 | + * | |
341 | + * make pr_debug()/dev_dbg() calls runtime configurable based upon their | |
342 | + * their source module. | |
343 | + * | |
344 | + * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com> | |
345 | + */ | |
346 | + | |
347 | +#include <linux/kernel.h> | |
348 | +#include <linux/module.h> | |
349 | +#include <linux/uaccess.h> | |
350 | +#include <linux/seq_file.h> | |
351 | +#include <linux/debugfs.h> | |
352 | +#include <linux/fs.h> | |
353 | + | |
354 | +extern struct mod_debug __start___verbose[]; | |
355 | +extern struct mod_debug __stop___verbose[]; | |
356 | + | |
357 | +struct debug_name { | |
358 | + struct hlist_node hlist; | |
359 | + struct hlist_node hlist2; | |
360 | + int hash1; | |
361 | + int hash2; | |
362 | + char *name; | |
363 | + int enable; | |
364 | + int type; | |
365 | +}; | |
366 | + | |
367 | +static int nr_entries; | |
368 | +static int num_enabled; | |
369 | +int dynamic_enabled = DYNAMIC_ENABLED_NONE; | |
370 | +static struct hlist_head module_table[DEBUG_HASH_TABLE_SIZE] = | |
371 | + { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT }; | |
372 | +static struct hlist_head module_table2[DEBUG_HASH_TABLE_SIZE] = | |
373 | + { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT }; | |
374 | +static DECLARE_MUTEX(debug_list_mutex); | |
375 | + | |
376 | +/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which | |
377 | + * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They | |
378 | + * use independent hash functions, to reduce the chance of false positives. | |
379 | + */ | |
380 | +long long dynamic_printk_enabled; | |
381 | +EXPORT_SYMBOL_GPL(dynamic_printk_enabled); | |
382 | +long long dynamic_printk_enabled2; | |
383 | +EXPORT_SYMBOL_GPL(dynamic_printk_enabled2); | |
384 | + | |
385 | +/* returns the debug module pointer. */ | |
386 | +static struct debug_name *find_debug_module(char *module_name) | |
387 | +{ | |
388 | + int i; | |
389 | + struct hlist_head *head; | |
390 | + struct hlist_node *node; | |
391 | + struct debug_name *element; | |
392 | + | |
393 | + element = NULL; | |
394 | + for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) { | |
395 | + head = &module_table[i]; | |
396 | + hlist_for_each_entry_rcu(element, node, head, hlist) | |
397 | + if (!strcmp(element->name, module_name)) | |
398 | + return element; | |
399 | + } | |
400 | + return NULL; | |
401 | +} | |
402 | + | |
403 | +/* returns the debug module pointer. */ | |
404 | +static struct debug_name *find_debug_module_hash(char *module_name, int hash) | |
405 | +{ | |
406 | + struct hlist_head *head; | |
407 | + struct hlist_node *node; | |
408 | + struct debug_name *element; | |
409 | + | |
410 | + element = NULL; | |
411 | + head = &module_table[hash]; | |
412 | + hlist_for_each_entry_rcu(element, node, head, hlist) | |
413 | + if (!strcmp(element->name, module_name)) | |
414 | + return element; | |
415 | + return NULL; | |
416 | +} | |
417 | + | |
418 | +/* caller must hold mutex*/ | |
419 | +static int __add_debug_module(char *mod_name, int hash, int hash2) | |
420 | +{ | |
421 | + struct debug_name *new; | |
422 | + char *module_name; | |
423 | + int ret = 0; | |
424 | + | |
425 | + if (find_debug_module(mod_name)) { | |
426 | + ret = -EINVAL; | |
427 | + goto out; | |
428 | + } | |
429 | + module_name = kmalloc(strlen(mod_name) + 1, GFP_KERNEL); | |
430 | + if (!module_name) { | |
431 | + ret = -ENOMEM; | |
432 | + goto out; | |
433 | + } | |
434 | + module_name = strcpy(module_name, mod_name); | |
435 | + module_name[strlen(mod_name)] = '\0'; | |
436 | + new = kzalloc(sizeof(struct debug_name), GFP_KERNEL); | |
437 | + if (!new) { | |
438 | + kfree(module_name); | |
439 | + ret = -ENOMEM; | |
440 | + goto out; | |
441 | + } | |
442 | + INIT_HLIST_NODE(&new->hlist); | |
443 | + INIT_HLIST_NODE(&new->hlist2); | |
444 | + new->name = module_name; | |
445 | + new->hash1 = hash; | |
446 | + new->hash2 = hash2; | |
447 | + hlist_add_head_rcu(&new->hlist, &module_table[hash]); | |
448 | + hlist_add_head_rcu(&new->hlist2, &module_table2[hash2]); | |
449 | + nr_entries++; | |
450 | +out: | |
451 | + return ret; | |
452 | +} | |
453 | + | |
454 | +int unregister_dynamic_debug_module(char *mod_name) | |
455 | +{ | |
456 | + struct debug_name *element; | |
457 | + int ret = 0; | |
458 | + | |
459 | + down(&debug_list_mutex); | |
460 | + element = find_debug_module(mod_name); | |
461 | + if (!element) { | |
462 | + ret = -EINVAL; | |
463 | + goto out; | |
464 | + } | |
465 | + hlist_del_rcu(&element->hlist); | |
466 | + hlist_del_rcu(&element->hlist2); | |
467 | + synchronize_rcu(); | |
468 | + kfree(element->name); | |
469 | + if (element->enable) | |
470 | + num_enabled--; | |
471 | + kfree(element); | |
472 | + nr_entries--; | |
473 | +out: | |
474 | + up(&debug_list_mutex); | |
475 | + return 0; | |
476 | +} | |
477 | +EXPORT_SYMBOL_GPL(unregister_dynamic_debug_module); | |
478 | + | |
479 | +int register_dynamic_debug_module(char *mod_name, int type, char *share_name, | |
480 | + char *flags, int hash, int hash2) | |
481 | +{ | |
482 | + struct debug_name *elem; | |
483 | + int ret = 0; | |
484 | + | |
485 | + down(&debug_list_mutex); | |
486 | + elem = find_debug_module(mod_name); | |
487 | + if (!elem) { | |
488 | + if (__add_debug_module(mod_name, hash, hash2)) | |
489 | + goto out; | |
490 | + elem = find_debug_module(mod_name); | |
491 | + if (dynamic_enabled == DYNAMIC_ENABLED_ALL && | |
492 | + !strcmp(mod_name, share_name)) { | |
493 | + elem->enable = true; | |
494 | + num_enabled++; | |
495 | + } | |
496 | + } | |
497 | + elem->type |= type; | |
498 | +out: | |
499 | + up(&debug_list_mutex); | |
500 | + return ret; | |
501 | +} | |
502 | +EXPORT_SYMBOL_GPL(register_dynamic_debug_module); | |
503 | + | |
504 | +int __dynamic_dbg_enabled_helper(char *mod_name, int type, int value, int hash) | |
505 | +{ | |
506 | + struct debug_name *elem; | |
507 | + int ret = 0; | |
508 | + | |
509 | + if (dynamic_enabled == DYNAMIC_ENABLED_ALL) | |
510 | + return 1; | |
511 | + rcu_read_lock(); | |
512 | + elem = find_debug_module_hash(mod_name, hash); | |
513 | + if (elem && elem->enable) | |
514 | + ret = 1; | |
515 | + rcu_read_unlock(); | |
516 | + return ret; | |
517 | +} | |
518 | +EXPORT_SYMBOL_GPL(__dynamic_dbg_enabled_helper); | |
519 | + | |
520 | +static void set_all(bool enable) | |
521 | +{ | |
522 | + struct debug_name *e; | |
523 | + struct hlist_node *node; | |
524 | + int i; | |
525 | + long long enable_mask; | |
526 | + | |
527 | + for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) { | |
528 | + if (module_table[i].first != NULL) { | |
529 | + hlist_for_each_entry(e, node, &module_table[i], hlist) { | |
530 | + e->enable = enable; | |
531 | + } | |
532 | + } | |
533 | + } | |
534 | + if (enable) | |
535 | + enable_mask = ULLONG_MAX; | |
536 | + else | |
537 | + enable_mask = 0; | |
538 | + dynamic_printk_enabled = enable_mask; | |
539 | + dynamic_printk_enabled2 = enable_mask; | |
540 | +} | |
541 | + | |
542 | +static int disabled_hash(int i, bool first_table) | |
543 | +{ | |
544 | + struct debug_name *e; | |
545 | + struct hlist_node *node; | |
546 | + | |
547 | + if (first_table) { | |
548 | + hlist_for_each_entry(e, node, &module_table[i], hlist) { | |
549 | + if (e->enable) | |
550 | + return 0; | |
551 | + } | |
552 | + } else { | |
553 | + hlist_for_each_entry(e, node, &module_table2[i], hlist2) { | |
554 | + if (e->enable) | |
555 | + return 0; | |
556 | + } | |
557 | + } | |
558 | + return 1; | |
559 | +} | |
560 | + | |
561 | +static ssize_t pr_debug_write(struct file *file, const char __user *buf, | |
562 | + size_t length, loff_t *ppos) | |
563 | +{ | |
564 | + char *buffer, *s, *value_str, *setting_str; | |
565 | + int err, value; | |
566 | + struct debug_name *elem = NULL; | |
567 | + int all = 0; | |
568 | + | |
569 | + if (length > PAGE_SIZE || length < 0) | |
570 | + return -EINVAL; | |
571 | + | |
572 | + buffer = (char *)__get_free_page(GFP_KERNEL); | |
573 | + if (!buffer) | |
574 | + return -ENOMEM; | |
575 | + | |
576 | + err = -EFAULT; | |
577 | + if (copy_from_user(buffer, buf, length)) | |
578 | + goto out; | |
579 | + | |
580 | + err = -EINVAL; | |
581 | + if (length < PAGE_SIZE) | |
582 | + buffer[length] = '\0'; | |
583 | + else if (buffer[PAGE_SIZE-1]) | |
584 | + goto out; | |
585 | + | |
586 | + err = -EINVAL; | |
587 | + down(&debug_list_mutex); | |
588 | + | |
589 | + if (strncmp("set", buffer, 3)) | |
590 | + goto out_up; | |
591 | + s = buffer + 3; | |
592 | + setting_str = strsep(&s, "="); | |
593 | + if (s == NULL) | |
594 | + goto out_up; | |
595 | + setting_str = strstrip(setting_str); | |
596 | + value_str = strsep(&s, " "); | |
597 | + if (s == NULL) | |
598 | + goto out_up; | |
599 | + s = strstrip(s); | |
600 | + if (!strncmp(s, "all", 3)) | |
601 | + all = 1; | |
602 | + else | |
603 | + elem = find_debug_module(s); | |
604 | + if (!strncmp(setting_str, "enable", 6)) { | |
605 | + value = !!simple_strtol(value_str, NULL, 10); | |
606 | + if (all) { | |
607 | + if (value) { | |
608 | + set_all(true); | |
609 | + num_enabled = nr_entries; | |
610 | + dynamic_enabled = DYNAMIC_ENABLED_ALL; | |
611 | + } else { | |
612 | + set_all(false); | |
613 | + num_enabled = 0; | |
614 | + dynamic_enabled = DYNAMIC_ENABLED_NONE; | |
615 | + } | |
616 | + err = 0; | |
617 | + } else { | |
618 | + if (elem) { | |
619 | + if (value && (elem->enable == 0)) { | |
620 | + dynamic_printk_enabled |= | |
621 | + (1LL << elem->hash1); | |
622 | + dynamic_printk_enabled2 |= | |
623 | + (1LL << elem->hash2); | |
624 | + elem->enable = 1; | |
625 | + num_enabled++; | |
626 | + dynamic_enabled = DYNAMIC_ENABLED_SOME; | |
627 | + err = 0; | |
628 | + printk(KERN_DEBUG | |
629 | + "debugging enabled for module %s", | |
630 | + elem->name); | |
631 | + } else if (!value && (elem->enable == 1)) { | |
632 | + elem->enable = 0; | |
633 | + num_enabled--; | |
634 | + if (disabled_hash(elem->hash1, true)) | |
635 | + dynamic_printk_enabled &= | |
636 | + ~(1LL << elem->hash1); | |
637 | + if (disabled_hash(elem->hash2, false)) | |
638 | + dynamic_printk_enabled2 &= | |
639 | + ~(1LL << elem->hash2); | |
640 | + if (num_enabled) | |
641 | + dynamic_enabled = | |
642 | + DYNAMIC_ENABLED_SOME; | |
643 | + else | |
644 | + dynamic_enabled = | |
645 | + DYNAMIC_ENABLED_NONE; | |
646 | + err = 0; | |
647 | + printk(KERN_DEBUG | |
648 | + "debugging disabled for module " | |
649 | + "%s", elem->name); | |
650 | + } | |
651 | + } | |
652 | + } | |
653 | + } | |
654 | + if (!err) | |
655 | + err = length; | |
656 | +out_up: | |
657 | + up(&debug_list_mutex); | |
658 | +out: | |
659 | + free_page((unsigned long)buffer); | |
660 | + return err; | |
661 | +} | |
662 | + | |
663 | +static void *pr_debug_seq_start(struct seq_file *f, loff_t *pos) | |
664 | +{ | |
665 | + return (*pos < DEBUG_HASH_TABLE_SIZE) ? pos : NULL; | |
666 | +} | |
667 | + | |
668 | +static void *pr_debug_seq_next(struct seq_file *s, void *v, loff_t *pos) | |
669 | +{ | |
670 | + (*pos)++; | |
671 | + if (*pos >= DEBUG_HASH_TABLE_SIZE) | |
672 | + return NULL; | |
673 | + return pos; | |
674 | +} | |
675 | + | |
676 | +static void pr_debug_seq_stop(struct seq_file *s, void *v) | |
677 | +{ | |
678 | + /* Nothing to do */ | |
679 | +} | |
680 | + | |
681 | +static int pr_debug_seq_show(struct seq_file *s, void *v) | |
682 | +{ | |
683 | + struct hlist_head *head; | |
684 | + struct hlist_node *node; | |
685 | + struct debug_name *elem; | |
686 | + unsigned int i = *(loff_t *) v; | |
687 | + | |
688 | + rcu_read_lock(); | |
689 | + head = &module_table[i]; | |
690 | + hlist_for_each_entry_rcu(elem, node, head, hlist) { | |
691 | + seq_printf(s, "%s enabled=%d", elem->name, elem->enable); | |
692 | + seq_printf(s, "\n"); | |
693 | + } | |
694 | + rcu_read_unlock(); | |
695 | + return 0; | |
696 | +} | |
697 | + | |
698 | +static struct seq_operations pr_debug_seq_ops = { | |
699 | + .start = pr_debug_seq_start, | |
700 | + .next = pr_debug_seq_next, | |
701 | + .stop = pr_debug_seq_stop, | |
702 | + .show = pr_debug_seq_show | |
703 | +}; | |
704 | + | |
705 | +static int pr_debug_open(struct inode *inode, struct file *filp) | |
706 | +{ | |
707 | + return seq_open(filp, &pr_debug_seq_ops); | |
708 | +} | |
709 | + | |
710 | +static const struct file_operations pr_debug_operations = { | |
711 | + .open = pr_debug_open, | |
712 | + .read = seq_read, | |
713 | + .write = pr_debug_write, | |
714 | + .llseek = seq_lseek, | |
715 | + .release = seq_release, | |
716 | +}; | |
717 | + | |
718 | +static int __init dynamic_printk_init(void) | |
719 | +{ | |
720 | + struct dentry *dir, *file; | |
721 | + struct mod_debug *iter; | |
722 | + unsigned long value; | |
723 | + | |
724 | + dir = debugfs_create_dir("dynamic_printk", NULL); | |
725 | + if (!dir) | |
726 | + return -ENOMEM; | |
727 | + file = debugfs_create_file("modules", 0644, dir, NULL, | |
728 | + &pr_debug_operations); | |
729 | + if (!file) { | |
730 | + debugfs_remove(dir); | |
731 | + return -ENOMEM; | |
732 | + } | |
733 | + for (value = (unsigned long)__start___verbose; | |
734 | + value < (unsigned long)__stop___verbose; | |
735 | + value += sizeof(struct mod_debug)) { | |
736 | + iter = (struct mod_debug *)value; | |
737 | + register_dynamic_debug_module(iter->modname, | |
738 | + iter->type, | |
739 | + iter->logical_modname, | |
740 | + iter->flag_names, iter->hash, iter->hash2); | |
741 | + } | |
742 | + return 0; | |
743 | +} | |
744 | +module_init(dynamic_printk_init); | |
745 | +/* may want to move this earlier so we can get traces as early as possible */ | |
746 | + | |
747 | +static int __init dynamic_printk_setup(char *str) | |
748 | +{ | |
749 | + if (str) | |
750 | + return -ENOENT; | |
751 | + set_all(true); | |
752 | + return 0; | |
753 | +} | |
754 | +/* Use early_param(), so we can get debug output as early as possible */ | |
755 | +early_param("dynamic_printk", dynamic_printk_setup); | |
756 | --- a/lib/Kconfig.debug | |
757 | +++ b/lib/Kconfig.debug | |
758 | @@ -752,6 +752,61 @@ menuconfig BUILD_DOCSRC | |
759 | ||
760 | Say N if you are unsure. | |
761 | ||
762 | +config DYNAMIC_PRINTK_DEBUG | |
763 | + bool "Enable dynamic printk() call support" | |
764 | + default n | |
765 | + depends on PRINTK | |
766 | + select PRINTK_DEBUG | |
767 | + help | |
768 | + | |
769 | + Compiles debug level messages into the kernel, which would not | |
770 | + otherwise be available at runtime. These messages can then be | |
771 | + enabled/disabled on a per module basis. This mechanism implicitly | |
772 | + enables all pr_debug() and dev_dbg() calls. The impact of this | |
773 | + compile option is a larger kernel text size of about 2%. | |
774 | + | |
775 | + Usage: | |
776 | + | |
777 | + Dynamic debugging is controlled by the debugfs file, | |
778 | + dynamic_printk/modules. This file contains a list of the modules that | |
779 | + can be enabled. The format of the file is the module name, followed | |
780 | + by a set of flags that can be enabled. The first flag is always the | |
781 | + 'enabled' flag. For example: | |
782 | + | |
783 | + <module_name> <enabled=0/1> | |
784 | + . | |
785 | + . | |
786 | + . | |
787 | + | |
788 | + <module_name> : Name of the module in which the debug call resides | |
789 | + <enabled=0/1> : whether the messages are enabled or not | |
790 | + | |
791 | + From a live system: | |
792 | + | |
793 | + snd_hda_intel enabled=0 | |
794 | + fixup enabled=0 | |
795 | + driver enabled=0 | |
796 | + | |
797 | + Enable a module: | |
798 | + | |
799 | + $echo "set enabled=1 <module_name>" > dynamic_printk/modules | |
800 | + | |
801 | + Disable a module: | |
802 | + | |
803 | + $echo "set enabled=0 <module_name>" > dynamic_printk/modules | |
804 | + | |
805 | + Enable all modules: | |
806 | + | |
807 | + $echo "set enabled=1 all" > dynamic_printk/modules | |
808 | + | |
809 | + Disable all modules: | |
810 | + | |
811 | + $echo "set enabled=0 all" > dynamic_printk/modules | |
812 | + | |
813 | + Finally, passing "dynamic_printk" at the command line enables | |
814 | + debugging for all modules. This mode can be turned off via the above | |
815 | + disable command. | |
816 | + | |
817 | source "samples/Kconfig" | |
818 | ||
819 | source "lib/Kconfig.kgdb" | |
820 | --- a/lib/Makefile | |
821 | +++ b/lib/Makefile | |
822 | @@ -81,6 +81,8 @@ obj-$(CONFIG_HAVE_LMB) += lmb.o | |
823 | ||
824 | obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) += syscall.o | |
825 | ||
826 | +obj-$(CONFIG_DYNAMIC_PRINTK_DEBUG) += dynamic_printk.o | |
827 | + | |
828 | hostprogs-y := gen_crc32table | |
829 | clean-files := crc32table.h | |
830 | ||
831 | --- a/net/netfilter/nf_conntrack_pptp.c | |
832 | +++ b/net/netfilter/nf_conntrack_pptp.c | |
833 | @@ -65,7 +65,7 @@ void | |
834 | struct nf_conntrack_expect *exp) __read_mostly; | |
835 | EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn); | |
836 | ||
837 | -#ifdef DEBUG | |
838 | +#if defined(DEBUG) || defined(CONFIG_DYNAMIC_PRINTK_DEBUG) | |
839 | /* PptpControlMessageType names */ | |
840 | const char *const pptp_msg_name[] = { | |
841 | "UNKNOWN_MESSAGE", | |
842 | --- /dev/null | |
843 | +++ b/scripts/basic/hash.c | |
844 | @@ -0,0 +1,64 @@ | |
845 | +/* | |
846 | + * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com> | |
847 | + * | |
848 | + */ | |
849 | + | |
850 | +#include <stdio.h> | |
851 | +#include <stdlib.h> | |
852 | +#include <string.h> | |
853 | + | |
854 | +#define DYNAMIC_DEBUG_HASH_BITS 6 | |
855 | + | |
856 | +static const char *program; | |
857 | + | |
858 | +static void usage(void) | |
859 | +{ | |
860 | + printf("Usage: %s <djb2|r5> <modname>\n", program); | |
861 | + exit(1); | |
862 | +} | |
863 | + | |
864 | +/* djb2 hashing algorithm by Dan Bernstein. From: | |
865 | + * http://www.cse.yorku.ca/~oz/hash.html | |
866 | + */ | |
867 | + | |
868 | +unsigned int djb2_hash(char *str) | |
869 | +{ | |
870 | + unsigned long hash = 5381; | |
871 | + int c; | |
872 | + | |
873 | + c = *str; | |
874 | + while (c) { | |
875 | + hash = ((hash << 5) + hash) + c; | |
876 | + c = *++str; | |
877 | + } | |
878 | + return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1)); | |
879 | +} | |
880 | + | |
881 | +unsigned int r5_hash(char *str) | |
882 | +{ | |
883 | + unsigned long hash = 0; | |
884 | + int c; | |
885 | + | |
886 | + c = *str; | |
887 | + while (c) { | |
888 | + hash = (hash + (c << 4) + (c >> 4)) * 11; | |
889 | + c = *++str; | |
890 | + } | |
891 | + return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1)); | |
892 | +} | |
893 | + | |
894 | +int main(int argc, char *argv[]) | |
895 | +{ | |
896 | + program = argv[0]; | |
897 | + | |
898 | + if (argc != 3) | |
899 | + usage(); | |
900 | + if (!strcmp(argv[1], "djb2")) | |
901 | + printf("%d\n", djb2_hash(argv[2])); | |
902 | + else if (!strcmp(argv[1], "r5")) | |
903 | + printf("%d\n", r5_hash(argv[2])); | |
904 | + else | |
905 | + usage(); | |
906 | + exit(0); | |
907 | +} | |
908 | + | |
909 | --- a/scripts/basic/Makefile | |
910 | +++ b/scripts/basic/Makefile | |
911 | @@ -9,7 +9,7 @@ | |
912 | # fixdep: Used to generate dependency information during build process | |
913 | # docproc: Used in Documentation/DocBook | |
914 | ||
915 | -hostprogs-y := fixdep docproc | |
916 | +hostprogs-y := fixdep docproc hash | |
917 | always := $(hostprogs-y) | |
918 | ||
919 | # fixdep is needed to compile other host programs | |
920 | --- a/scripts/Makefile.lib | |
921 | +++ b/scripts/Makefile.lib | |
922 | @@ -96,6 +96,14 @@ basename_flags = -D"KBUILD_BASENAME=KBUI | |
923 | modname_flags = $(if $(filter 1,$(words $(modname))),\ | |
924 | -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") | |
925 | ||
926 | +#hash values | |
927 | +ifdef CONFIG_DYNAMIC_PRINTK_DEBUG | |
928 | +debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\ | |
929 | + -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))" | |
930 | +else | |
931 | +debug_flags = | |
932 | +endif | |
933 | + | |
934 | orig_c_flags = $(KBUILD_CFLAGS) $(ccflags-y) $(CFLAGS_$(basetarget).o) | |
935 | _c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags)) | |
936 | _a_flags = $(KBUILD_AFLAGS) $(asflags-y) $(AFLAGS_$(basetarget).o) | |
937 | @@ -121,7 +129,8 @@ endif | |
938 | ||
939 | c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \ | |
940 | $(__c_flags) $(modkern_cflags) \ | |
941 | - -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) | |
942 | + -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \ | |
943 | + $(debug_flags) | |
944 | ||
945 | a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \ | |
946 | $(__a_flags) $(modkern_aflags) |