Commit 346e15beb5343c2eb8216d820f2ed8f150822b08
Committed by
Greg Kroah-Hartman
1 parent
33376c1c04
Exists in
master
and in
4 other branches
driver core: basic infrastructure for per-module dynamic debug messages
Base infrastructure to enable per-module debug messages. I've introduced CONFIG_DYNAMIC_PRINTK_DEBUG, which when enabled centralizes control of debugging statements on a per-module basis in one /proc file, currently, <debugfs>/dynamic_printk/modules. When, CONFIG_DYNAMIC_PRINTK_DEBUG, is not set, debugging statements can still be enabled as before, often by defining 'DEBUG' for the proper compilation unit. Thus, this patch set has no affect when CONFIG_DYNAMIC_PRINTK_DEBUG is not set. The infrastructure currently ties into all pr_debug() and dev_dbg() calls. That is, if CONFIG_DYNAMIC_PRINTK_DEBUG is set, all pr_debug() and dev_dbg() calls can be dynamically enabled/disabled on a per-module basis. Future plans include extending this functionality to subsystems, that define their own debug levels and flags. Usage: Dynamic debugging is controlled by the debugfs file, <debugfs>/dynamic_printk/modules. This file contains a list of the modules that can be enabled. The format of the file is as follows: <module_name> <enabled=0/1> . . . <module_name> : Name of the module in which the debug call resides <enabled=0/1> : whether the messages are enabled or not For example: snd_hda_intel enabled=0 fixup enabled=1 driver enabled=0 Enable a module: $echo "set enabled=1 <module_name>" > dynamic_printk/modules Disable a module: $echo "set enabled=0 <module_name>" > dynamic_printk/modules Enable all modules: $echo "set enabled=1 all" > dynamic_printk/modules Disable all modules: $echo "set enabled=0 all" > dynamic_printk/modules Finally, passing "dynamic_printk" at the command line enables debugging for all modules. This mode can be turned off via the above disable command. [gkh: minor cleanups and tweaks to make the build work quietly] Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 14 changed files with 700 additions and 7 deletions Side-by-side Diff
- Documentation/kernel-parameters.txt
- include/asm-generic/vmlinux.lds.h
- include/linux/device.h
- include/linux/dynamic_printk.h
- include/linux/kernel.h
- include/linux/module.h
- kernel/module.c
- lib/Kconfig.debug
- lib/Makefile
- lib/dynamic_printk.c
- net/netfilter/nf_conntrack_pptp.c
- scripts/Makefile.lib
- scripts/basic/Makefile
- scripts/basic/hash.c
Documentation/kernel-parameters.txt
... | ... | @@ -1713,6 +1713,11 @@ |
1713 | 1713 | autoconfiguration. |
1714 | 1714 | Ranges are in pairs (memory base and size). |
1715 | 1715 | |
1716 | + dynamic_printk | |
1717 | + Enables pr_debug()/dev_dbg() calls if | |
1718 | + CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled. These can also | |
1719 | + be switched on/off via <debugfs>/dynamic_printk/modules | |
1720 | + | |
1716 | 1721 | print-fatal-signals= |
1717 | 1722 | [KNL] debug: print fatal signals |
1718 | 1723 | print-fatal-signals=1: print segfault info to |
include/asm-generic/vmlinux.lds.h
... | ... | @@ -268,7 +268,15 @@ |
268 | 268 | CPU_DISCARD(init.data) \ |
269 | 269 | CPU_DISCARD(init.rodata) \ |
270 | 270 | MEM_DISCARD(init.data) \ |
271 | - MEM_DISCARD(init.rodata) | |
271 | + MEM_DISCARD(init.rodata) \ | |
272 | + /* implement dynamic printk debug */ \ | |
273 | + VMLINUX_SYMBOL(__start___verbose_strings) = .; \ | |
274 | + *(__verbose_strings) \ | |
275 | + VMLINUX_SYMBOL(__stop___verbose_strings) = .; \ | |
276 | + . = ALIGN(8); \ | |
277 | + VMLINUX_SYMBOL(__start___verbose) = .; \ | |
278 | + *(__verbose) \ | |
279 | + VMLINUX_SYMBOL(__stop___verbose) = .; | |
272 | 280 | |
273 | 281 | #define INIT_TEXT \ |
274 | 282 | *(.init.text) \ |
include/linux/device.h
... | ... | @@ -550,7 +550,11 @@ |
550 | 550 | #define dev_info(dev, format, arg...) \ |
551 | 551 | dev_printk(KERN_INFO , dev , format , ## arg) |
552 | 552 | |
553 | -#ifdef DEBUG | |
553 | +#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG) | |
554 | +#define dev_dbg(dev, format, ...) do { \ | |
555 | + dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \ | |
556 | + } while (0) | |
557 | +#elif defined(DEBUG) | |
554 | 558 | #define dev_dbg(dev, format, arg...) \ |
555 | 559 | dev_printk(KERN_DEBUG , dev , format , ## arg) |
556 | 560 | #else |
include/linux/dynamic_printk.h
1 | +#ifndef _DYNAMIC_PRINTK_H | |
2 | +#define _DYNAMIC_PRINTK_H | |
3 | + | |
4 | +#define DYNAMIC_DEBUG_HASH_BITS 6 | |
5 | +#define DEBUG_HASH_TABLE_SIZE (1 << DYNAMIC_DEBUG_HASH_BITS) | |
6 | + | |
7 | +#define TYPE_BOOLEAN 1 | |
8 | + | |
9 | +#define DYNAMIC_ENABLED_ALL 0 | |
10 | +#define DYNAMIC_ENABLED_NONE 1 | |
11 | +#define DYNAMIC_ENABLED_SOME 2 | |
12 | + | |
13 | +extern int dynamic_enabled; | |
14 | + | |
15 | +/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which | |
16 | + * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They | |
17 | + * use independent hash functions, to reduce the chance of false positives. | |
18 | + */ | |
19 | +extern long long dynamic_printk_enabled; | |
20 | +extern long long dynamic_printk_enabled2; | |
21 | + | |
22 | +struct mod_debug { | |
23 | + char *modname; | |
24 | + char *logical_modname; | |
25 | + char *flag_names; | |
26 | + int type; | |
27 | + int hash; | |
28 | + int hash2; | |
29 | +} __attribute__((aligned(8))); | |
30 | + | |
31 | +int register_dynamic_debug_module(char *mod_name, int type, char *share_name, | |
32 | + char *flags, int hash, int hash2); | |
33 | + | |
34 | +#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG) | |
35 | +extern int unregister_dynamic_debug_module(char *mod_name); | |
36 | +extern int __dynamic_dbg_enabled_helper(char *modname, int type, | |
37 | + int value, int hash); | |
38 | + | |
39 | +#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ \ | |
40 | + int __ret = 0; \ | |
41 | + if (unlikely((dynamic_printk_enabled & (1LL << DEBUG_HASH)) && \ | |
42 | + (dynamic_printk_enabled2 & (1LL << DEBUG_HASH2)))) \ | |
43 | + __ret = __dynamic_dbg_enabled_helper(module, type, \ | |
44 | + value, hash);\ | |
45 | + __ret; }) | |
46 | + | |
47 | +#define dynamic_pr_debug(fmt, ...) do { \ | |
48 | + static char mod_name[] \ | |
49 | + __attribute__((section("__verbose_strings"))) \ | |
50 | + = KBUILD_MODNAME; \ | |
51 | + static struct mod_debug descriptor \ | |
52 | + __used \ | |
53 | + __attribute__((section("__verbose"), aligned(8))) = \ | |
54 | + { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\ | |
55 | + if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \ | |
56 | + 0, 0, DEBUG_HASH)) \ | |
57 | + printk(KERN_DEBUG KBUILD_MODNAME ":" fmt, \ | |
58 | + ##__VA_ARGS__); \ | |
59 | + } while (0) | |
60 | + | |
61 | +#define dynamic_dev_dbg(dev, format, ...) do { \ | |
62 | + static char mod_name[] \ | |
63 | + __attribute__((section("__verbose_strings"))) \ | |
64 | + = KBUILD_MODNAME; \ | |
65 | + static struct mod_debug descriptor \ | |
66 | + __used \ | |
67 | + __attribute__((section("__verbose"), aligned(8))) = \ | |
68 | + { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\ | |
69 | + if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \ | |
70 | + 0, 0, DEBUG_HASH)) \ | |
71 | + dev_printk(KERN_DEBUG, dev, \ | |
72 | + KBUILD_MODNAME ": " format, \ | |
73 | + ##__VA_ARGS__); \ | |
74 | + } while (0) | |
75 | + | |
76 | +#else | |
77 | + | |
78 | +static inline int unregister_dynamic_debug_module(const char *mod_name) | |
79 | +{ | |
80 | + return 0; | |
81 | +} | |
82 | +static inline int __dynamic_dbg_enabled_helper(char *modname, int type, | |
83 | + int value, int hash) | |
84 | +{ | |
85 | + return 0; | |
86 | +} | |
87 | + | |
88 | +#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ 0; }) | |
89 | +#define dynamic_pr_debug(fmt, ...) do { } while (0) | |
90 | +#define dynamic_dev_dbg(dev, format, ...) do { } while (0) | |
91 | +#endif | |
92 | + | |
93 | +#endif |
include/linux/kernel.h
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | #include <linux/log2.h> |
17 | 17 | #include <linux/typecheck.h> |
18 | 18 | #include <linux/ratelimit.h> |
19 | +#include <linux/dynamic_printk.h> | |
19 | 20 | #include <asm/byteorder.h> |
20 | 21 | #include <asm/bug.h> |
21 | 22 | |
22 | 23 | |
... | ... | @@ -303,8 +304,12 @@ |
303 | 304 | #define pr_info(fmt, arg...) \ |
304 | 305 | printk(KERN_INFO fmt, ##arg) |
305 | 306 | |
306 | -#ifdef DEBUG | |
307 | 307 | /* If you are writing a driver, please use dev_dbg instead */ |
308 | +#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG) | |
309 | +#define pr_debug(fmt, ...) do { \ | |
310 | + dynamic_pr_debug(fmt, ##__VA_ARGS__); \ | |
311 | + } while (0) | |
312 | +#elif defined(DEBUG) | |
308 | 313 | #define pr_debug(fmt, arg...) \ |
309 | 314 | printk(KERN_DEBUG fmt, ##arg) |
310 | 315 | #else |
include/linux/module.h
kernel/module.c
... | ... | @@ -784,6 +784,7 @@ |
784 | 784 | mutex_lock(&module_mutex); |
785 | 785 | /* Store the name of the last unloaded module for diagnostic purposes */ |
786 | 786 | strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module)); |
787 | + unregister_dynamic_debug_module(mod->name); | |
787 | 788 | free_module(mod); |
788 | 789 | |
789 | 790 | out: |
... | ... | @@ -1783,6 +1784,33 @@ |
1783 | 1784 | } |
1784 | 1785 | #endif /* CONFIG_KALLSYMS */ |
1785 | 1786 | |
1787 | +#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG | |
1788 | +static void dynamic_printk_setup(Elf_Shdr *sechdrs, unsigned int verboseindex) | |
1789 | +{ | |
1790 | + struct mod_debug *debug_info; | |
1791 | + unsigned long pos, end; | |
1792 | + unsigned int num_verbose; | |
1793 | + | |
1794 | + pos = sechdrs[verboseindex].sh_addr; | |
1795 | + num_verbose = sechdrs[verboseindex].sh_size / | |
1796 | + sizeof(struct mod_debug); | |
1797 | + end = pos + (num_verbose * sizeof(struct mod_debug)); | |
1798 | + | |
1799 | + for (; pos < end; pos += sizeof(struct mod_debug)) { | |
1800 | + debug_info = (struct mod_debug *)pos; | |
1801 | + register_dynamic_debug_module(debug_info->modname, | |
1802 | + debug_info->type, debug_info->logical_modname, | |
1803 | + debug_info->flag_names, debug_info->hash, | |
1804 | + debug_info->hash2); | |
1805 | + } | |
1806 | +} | |
1807 | +#else | |
1808 | +static inline void dynamic_printk_setup(Elf_Shdr *sechdrs, | |
1809 | + unsigned int verboseindex) | |
1810 | +{ | |
1811 | +} | |
1812 | +#endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */ | |
1813 | + | |
1786 | 1814 | static void *module_alloc_update_bounds(unsigned long size) |
1787 | 1815 | { |
1788 | 1816 | void *ret = module_alloc(size); |
... | ... | @@ -1831,6 +1859,7 @@ |
1831 | 1859 | #endif |
1832 | 1860 | unsigned int markersindex; |
1833 | 1861 | unsigned int markersstringsindex; |
1862 | + unsigned int verboseindex; | |
1834 | 1863 | struct module *mod; |
1835 | 1864 | long err = 0; |
1836 | 1865 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ |
... | ... | @@ -2117,6 +2146,7 @@ |
2117 | 2146 | markersindex = find_sec(hdr, sechdrs, secstrings, "__markers"); |
2118 | 2147 | markersstringsindex = find_sec(hdr, sechdrs, secstrings, |
2119 | 2148 | "__markers_strings"); |
2149 | + verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose"); | |
2120 | 2150 | |
2121 | 2151 | /* Now do relocations. */ |
2122 | 2152 | for (i = 1; i < hdr->e_shnum; i++) { |
... | ... | @@ -2167,6 +2197,7 @@ |
2167 | 2197 | marker_update_probe_range(mod->markers, |
2168 | 2198 | mod->markers + mod->num_markers); |
2169 | 2199 | #endif |
2200 | + dynamic_printk_setup(sechdrs, verboseindex); | |
2170 | 2201 | err = module_finalize(hdr, sechdrs, mod); |
2171 | 2202 | if (err < 0) |
2172 | 2203 | goto cleanup; |
lib/Kconfig.debug
... | ... | @@ -807,6 +807,61 @@ |
807 | 807 | |
808 | 808 | Say N if you are unsure. |
809 | 809 | |
810 | +config DYNAMIC_PRINTK_DEBUG | |
811 | + bool "Enable dynamic printk() call support" | |
812 | + default n | |
813 | + depends on PRINTK | |
814 | + select PRINTK_DEBUG | |
815 | + help | |
816 | + | |
817 | + Compiles debug level messages into the kernel, which would not | |
818 | + otherwise be available at runtime. These messages can then be | |
819 | + enabled/disabled on a per module basis. This mechanism implicitly | |
820 | + enables all pr_debug() and dev_dbg() calls. The impact of this | |
821 | + compile option is a larger kernel text size of about 2%. | |
822 | + | |
823 | + Usage: | |
824 | + | |
825 | + Dynamic debugging is controlled by the debugfs file, | |
826 | + dynamic_printk/modules. This file contains a list of the modules that | |
827 | + can be enabled. The format of the file is the module name, followed | |
828 | + by a set of flags that can be enabled. The first flag is always the | |
829 | + 'enabled' flag. For example: | |
830 | + | |
831 | + <module_name> <enabled=0/1> | |
832 | + . | |
833 | + . | |
834 | + . | |
835 | + | |
836 | + <module_name> : Name of the module in which the debug call resides | |
837 | + <enabled=0/1> : whether the messages are enabled or not | |
838 | + | |
839 | + From a live system: | |
840 | + | |
841 | + snd_hda_intel enabled=0 | |
842 | + fixup enabled=0 | |
843 | + driver enabled=0 | |
844 | + | |
845 | + Enable a module: | |
846 | + | |
847 | + $echo "set enabled=1 <module_name>" > dynamic_printk/modules | |
848 | + | |
849 | + Disable a module: | |
850 | + | |
851 | + $echo "set enabled=0 <module_name>" > dynamic_printk/modules | |
852 | + | |
853 | + Enable all modules: | |
854 | + | |
855 | + $echo "set enabled=1 all" > dynamic_printk/modules | |
856 | + | |
857 | + Disable all modules: | |
858 | + | |
859 | + $echo "set enabled=0 all" > dynamic_printk/modules | |
860 | + | |
861 | + Finally, passing "dynamic_printk" at the command line enables | |
862 | + debugging for all modules. This mode can be turned off via the above | |
863 | + disable command. | |
864 | + | |
810 | 865 | source "samples/Kconfig" |
811 | 866 | |
812 | 867 | source "lib/Kconfig.kgdb" |
lib/Makefile
lib/dynamic_printk.c
1 | +/* | |
2 | + * lib/dynamic_printk.c | |
3 | + * | |
4 | + * make pr_debug()/dev_dbg() calls runtime configurable based upon their | |
5 | + * their source module. | |
6 | + * | |
7 | + * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com> | |
8 | + */ | |
9 | + | |
10 | +#include <linux/kernel.h> | |
11 | +#include <linux/module.h> | |
12 | +#include <linux/uaccess.h> | |
13 | +#include <linux/seq_file.h> | |
14 | +#include <linux/debugfs.h> | |
15 | +#include <linux/fs.h> | |
16 | + | |
17 | +extern struct mod_debug __start___verbose[]; | |
18 | +extern struct mod_debug __stop___verbose[]; | |
19 | + | |
20 | +struct debug_name { | |
21 | + struct hlist_node hlist; | |
22 | + struct hlist_node hlist2; | |
23 | + int hash1; | |
24 | + int hash2; | |
25 | + char *name; | |
26 | + int enable; | |
27 | + int type; | |
28 | +}; | |
29 | + | |
30 | +static int nr_entries; | |
31 | +static int num_enabled; | |
32 | +int dynamic_enabled = DYNAMIC_ENABLED_NONE; | |
33 | +static struct hlist_head module_table[DEBUG_HASH_TABLE_SIZE] = | |
34 | + { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT }; | |
35 | +static struct hlist_head module_table2[DEBUG_HASH_TABLE_SIZE] = | |
36 | + { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT }; | |
37 | +static DECLARE_MUTEX(debug_list_mutex); | |
38 | + | |
39 | +/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which | |
40 | + * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They | |
41 | + * use independent hash functions, to reduce the chance of false positives. | |
42 | + */ | |
43 | +long long dynamic_printk_enabled; | |
44 | +EXPORT_SYMBOL_GPL(dynamic_printk_enabled); | |
45 | +long long dynamic_printk_enabled2; | |
46 | +EXPORT_SYMBOL_GPL(dynamic_printk_enabled2); | |
47 | + | |
48 | +/* returns the debug module pointer. */ | |
49 | +static struct debug_name *find_debug_module(char *module_name) | |
50 | +{ | |
51 | + int i; | |
52 | + struct hlist_head *head; | |
53 | + struct hlist_node *node; | |
54 | + struct debug_name *element; | |
55 | + | |
56 | + element = NULL; | |
57 | + for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) { | |
58 | + head = &module_table[i]; | |
59 | + hlist_for_each_entry_rcu(element, node, head, hlist) | |
60 | + if (!strcmp(element->name, module_name)) | |
61 | + return element; | |
62 | + } | |
63 | + return NULL; | |
64 | +} | |
65 | + | |
66 | +/* returns the debug module pointer. */ | |
67 | +static struct debug_name *find_debug_module_hash(char *module_name, int hash) | |
68 | +{ | |
69 | + struct hlist_head *head; | |
70 | + struct hlist_node *node; | |
71 | + struct debug_name *element; | |
72 | + | |
73 | + element = NULL; | |
74 | + head = &module_table[hash]; | |
75 | + hlist_for_each_entry_rcu(element, node, head, hlist) | |
76 | + if (!strcmp(element->name, module_name)) | |
77 | + return element; | |
78 | + return NULL; | |
79 | +} | |
80 | + | |
81 | +/* caller must hold mutex*/ | |
82 | +static int __add_debug_module(char *mod_name, int hash, int hash2) | |
83 | +{ | |
84 | + struct debug_name *new; | |
85 | + char *module_name; | |
86 | + int ret = 0; | |
87 | + | |
88 | + if (find_debug_module(mod_name)) { | |
89 | + ret = -EINVAL; | |
90 | + goto out; | |
91 | + } | |
92 | + module_name = kmalloc(strlen(mod_name) + 1, GFP_KERNEL); | |
93 | + if (!module_name) { | |
94 | + ret = -ENOMEM; | |
95 | + goto out; | |
96 | + } | |
97 | + module_name = strcpy(module_name, mod_name); | |
98 | + module_name[strlen(mod_name)] = '\0'; | |
99 | + new = kzalloc(sizeof(struct debug_name), GFP_KERNEL); | |
100 | + if (!new) { | |
101 | + kfree(module_name); | |
102 | + ret = -ENOMEM; | |
103 | + goto out; | |
104 | + } | |
105 | + INIT_HLIST_NODE(&new->hlist); | |
106 | + INIT_HLIST_NODE(&new->hlist2); | |
107 | + new->name = module_name; | |
108 | + new->hash1 = hash; | |
109 | + new->hash2 = hash2; | |
110 | + hlist_add_head_rcu(&new->hlist, &module_table[hash]); | |
111 | + hlist_add_head_rcu(&new->hlist2, &module_table2[hash2]); | |
112 | + nr_entries++; | |
113 | +out: | |
114 | + return ret; | |
115 | +} | |
116 | + | |
117 | +int unregister_dynamic_debug_module(char *mod_name) | |
118 | +{ | |
119 | + struct debug_name *element; | |
120 | + int ret = 0; | |
121 | + | |
122 | + down(&debug_list_mutex); | |
123 | + element = find_debug_module(mod_name); | |
124 | + if (!element) { | |
125 | + ret = -EINVAL; | |
126 | + goto out; | |
127 | + } | |
128 | + hlist_del_rcu(&element->hlist); | |
129 | + hlist_del_rcu(&element->hlist2); | |
130 | + synchronize_rcu(); | |
131 | + kfree(element->name); | |
132 | + if (element->enable) | |
133 | + num_enabled--; | |
134 | + kfree(element); | |
135 | + nr_entries--; | |
136 | +out: | |
137 | + up(&debug_list_mutex); | |
138 | + return 0; | |
139 | +} | |
140 | +EXPORT_SYMBOL_GPL(unregister_dynamic_debug_module); | |
141 | + | |
142 | +int register_dynamic_debug_module(char *mod_name, int type, char *share_name, | |
143 | + char *flags, int hash, int hash2) | |
144 | +{ | |
145 | + struct debug_name *elem; | |
146 | + int ret = 0; | |
147 | + | |
148 | + down(&debug_list_mutex); | |
149 | + elem = find_debug_module(mod_name); | |
150 | + if (!elem) { | |
151 | + if (__add_debug_module(mod_name, hash, hash2)) | |
152 | + goto out; | |
153 | + elem = find_debug_module(mod_name); | |
154 | + if (dynamic_enabled == DYNAMIC_ENABLED_ALL && | |
155 | + !strcmp(mod_name, share_name)) { | |
156 | + elem->enable = true; | |
157 | + num_enabled++; | |
158 | + } | |
159 | + } | |
160 | + elem->type |= type; | |
161 | +out: | |
162 | + up(&debug_list_mutex); | |
163 | + return ret; | |
164 | +} | |
165 | +EXPORT_SYMBOL_GPL(register_dynamic_debug_module); | |
166 | + | |
167 | +int __dynamic_dbg_enabled_helper(char *mod_name, int type, int value, int hash) | |
168 | +{ | |
169 | + struct debug_name *elem; | |
170 | + int ret = 0; | |
171 | + | |
172 | + if (dynamic_enabled == DYNAMIC_ENABLED_ALL) | |
173 | + return 1; | |
174 | + rcu_read_lock(); | |
175 | + elem = find_debug_module_hash(mod_name, hash); | |
176 | + if (elem && elem->enable) | |
177 | + ret = 1; | |
178 | + rcu_read_unlock(); | |
179 | + return ret; | |
180 | +} | |
181 | +EXPORT_SYMBOL_GPL(__dynamic_dbg_enabled_helper); | |
182 | + | |
183 | +static void set_all(bool enable) | |
184 | +{ | |
185 | + struct debug_name *e; | |
186 | + struct hlist_node *node; | |
187 | + int i; | |
188 | + long long enable_mask; | |
189 | + | |
190 | + for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) { | |
191 | + if (module_table[i].first != NULL) { | |
192 | + hlist_for_each_entry(e, node, &module_table[i], hlist) { | |
193 | + e->enable = enable; | |
194 | + } | |
195 | + } | |
196 | + } | |
197 | + if (enable) | |
198 | + enable_mask = ULLONG_MAX; | |
199 | + else | |
200 | + enable_mask = 0; | |
201 | + dynamic_printk_enabled = enable_mask; | |
202 | + dynamic_printk_enabled2 = enable_mask; | |
203 | +} | |
204 | + | |
205 | +static int disabled_hash(int i, bool first_table) | |
206 | +{ | |
207 | + struct debug_name *e; | |
208 | + struct hlist_node *node; | |
209 | + | |
210 | + if (first_table) { | |
211 | + hlist_for_each_entry(e, node, &module_table[i], hlist) { | |
212 | + if (e->enable) | |
213 | + return 0; | |
214 | + } | |
215 | + } else { | |
216 | + hlist_for_each_entry(e, node, &module_table2[i], hlist2) { | |
217 | + if (e->enable) | |
218 | + return 0; | |
219 | + } | |
220 | + } | |
221 | + return 1; | |
222 | +} | |
223 | + | |
224 | +static ssize_t pr_debug_write(struct file *file, const char __user *buf, | |
225 | + size_t length, loff_t *ppos) | |
226 | +{ | |
227 | + char *buffer, *s, *value_str, *setting_str; | |
228 | + int err, value; | |
229 | + struct debug_name *elem = NULL; | |
230 | + int all = 0; | |
231 | + | |
232 | + if (length > PAGE_SIZE || length < 0) | |
233 | + return -EINVAL; | |
234 | + | |
235 | + buffer = (char *)__get_free_page(GFP_KERNEL); | |
236 | + if (!buffer) | |
237 | + return -ENOMEM; | |
238 | + | |
239 | + err = -EFAULT; | |
240 | + if (copy_from_user(buffer, buf, length)) | |
241 | + goto out; | |
242 | + | |
243 | + err = -EINVAL; | |
244 | + if (length < PAGE_SIZE) | |
245 | + buffer[length] = '\0'; | |
246 | + else if (buffer[PAGE_SIZE-1]) | |
247 | + goto out; | |
248 | + | |
249 | + err = -EINVAL; | |
250 | + down(&debug_list_mutex); | |
251 | + | |
252 | + if (strncmp("set", buffer, 3)) | |
253 | + goto out_up; | |
254 | + s = buffer + 3; | |
255 | + setting_str = strsep(&s, "="); | |
256 | + if (s == NULL) | |
257 | + goto out_up; | |
258 | + setting_str = strstrip(setting_str); | |
259 | + value_str = strsep(&s, " "); | |
260 | + if (s == NULL) | |
261 | + goto out_up; | |
262 | + s = strstrip(s); | |
263 | + if (!strncmp(s, "all", 3)) | |
264 | + all = 1; | |
265 | + else | |
266 | + elem = find_debug_module(s); | |
267 | + if (!strncmp(setting_str, "enable", 6)) { | |
268 | + value = !!simple_strtol(value_str, NULL, 10); | |
269 | + if (all) { | |
270 | + if (value) { | |
271 | + set_all(true); | |
272 | + num_enabled = nr_entries; | |
273 | + dynamic_enabled = DYNAMIC_ENABLED_ALL; | |
274 | + } else { | |
275 | + set_all(false); | |
276 | + num_enabled = 0; | |
277 | + dynamic_enabled = DYNAMIC_ENABLED_NONE; | |
278 | + } | |
279 | + err = 0; | |
280 | + } else { | |
281 | + if (elem) { | |
282 | + if (value && (elem->enable == 0)) { | |
283 | + dynamic_printk_enabled |= | |
284 | + (1LL << elem->hash1); | |
285 | + dynamic_printk_enabled2 |= | |
286 | + (1LL << elem->hash2); | |
287 | + elem->enable = 1; | |
288 | + num_enabled++; | |
289 | + dynamic_enabled = DYNAMIC_ENABLED_SOME; | |
290 | + err = 0; | |
291 | + printk(KERN_DEBUG | |
292 | + "debugging enabled for module %s", | |
293 | + elem->name); | |
294 | + } else if (!value && (elem->enable == 1)) { | |
295 | + elem->enable = 0; | |
296 | + num_enabled--; | |
297 | + if (disabled_hash(elem->hash1, true)) | |
298 | + dynamic_printk_enabled &= | |
299 | + ~(1LL << elem->hash1); | |
300 | + if (disabled_hash(elem->hash2, false)) | |
301 | + dynamic_printk_enabled2 &= | |
302 | + ~(1LL << elem->hash2); | |
303 | + if (num_enabled) | |
304 | + dynamic_enabled = | |
305 | + DYNAMIC_ENABLED_SOME; | |
306 | + else | |
307 | + dynamic_enabled = | |
308 | + DYNAMIC_ENABLED_NONE; | |
309 | + err = 0; | |
310 | + printk(KERN_DEBUG | |
311 | + "debugging disabled for module " | |
312 | + "%s", elem->name); | |
313 | + } | |
314 | + } | |
315 | + } | |
316 | + } | |
317 | + if (!err) | |
318 | + err = length; | |
319 | +out_up: | |
320 | + up(&debug_list_mutex); | |
321 | +out: | |
322 | + free_page((unsigned long)buffer); | |
323 | + return err; | |
324 | +} | |
325 | + | |
326 | +static void *pr_debug_seq_start(struct seq_file *f, loff_t *pos) | |
327 | +{ | |
328 | + return (*pos < DEBUG_HASH_TABLE_SIZE) ? pos : NULL; | |
329 | +} | |
330 | + | |
331 | +static void *pr_debug_seq_next(struct seq_file *s, void *v, loff_t *pos) | |
332 | +{ | |
333 | + (*pos)++; | |
334 | + if (*pos >= DEBUG_HASH_TABLE_SIZE) | |
335 | + return NULL; | |
336 | + return pos; | |
337 | +} | |
338 | + | |
339 | +static void pr_debug_seq_stop(struct seq_file *s, void *v) | |
340 | +{ | |
341 | + /* Nothing to do */ | |
342 | +} | |
343 | + | |
344 | +static int pr_debug_seq_show(struct seq_file *s, void *v) | |
345 | +{ | |
346 | + struct hlist_head *head; | |
347 | + struct hlist_node *node; | |
348 | + struct debug_name *elem; | |
349 | + unsigned int i = *(loff_t *) v; | |
350 | + | |
351 | + rcu_read_lock(); | |
352 | + head = &module_table[i]; | |
353 | + hlist_for_each_entry_rcu(elem, node, head, hlist) { | |
354 | + seq_printf(s, "%s enabled=%d", elem->name, elem->enable); | |
355 | + seq_printf(s, "\n"); | |
356 | + } | |
357 | + rcu_read_unlock(); | |
358 | + return 0; | |
359 | +} | |
360 | + | |
361 | +static struct seq_operations pr_debug_seq_ops = { | |
362 | + .start = pr_debug_seq_start, | |
363 | + .next = pr_debug_seq_next, | |
364 | + .stop = pr_debug_seq_stop, | |
365 | + .show = pr_debug_seq_show | |
366 | +}; | |
367 | + | |
368 | +static int pr_debug_open(struct inode *inode, struct file *filp) | |
369 | +{ | |
370 | + return seq_open(filp, &pr_debug_seq_ops); | |
371 | +} | |
372 | + | |
373 | +static const struct file_operations pr_debug_operations = { | |
374 | + .open = pr_debug_open, | |
375 | + .read = seq_read, | |
376 | + .write = pr_debug_write, | |
377 | + .llseek = seq_lseek, | |
378 | + .release = seq_release, | |
379 | +}; | |
380 | + | |
381 | +static int __init dynamic_printk_init(void) | |
382 | +{ | |
383 | + struct dentry *dir, *file; | |
384 | + struct mod_debug *iter; | |
385 | + unsigned long value; | |
386 | + | |
387 | + dir = debugfs_create_dir("dynamic_printk", NULL); | |
388 | + if (!dir) | |
389 | + return -ENOMEM; | |
390 | + file = debugfs_create_file("modules", 0644, dir, NULL, | |
391 | + &pr_debug_operations); | |
392 | + if (!file) { | |
393 | + debugfs_remove(dir); | |
394 | + return -ENOMEM; | |
395 | + } | |
396 | + for (value = (unsigned long)__start___verbose; | |
397 | + value < (unsigned long)__stop___verbose; | |
398 | + value += sizeof(struct mod_debug)) { | |
399 | + iter = (struct mod_debug *)value; | |
400 | + register_dynamic_debug_module(iter->modname, | |
401 | + iter->type, | |
402 | + iter->logical_modname, | |
403 | + iter->flag_names, iter->hash, iter->hash2); | |
404 | + } | |
405 | + return 0; | |
406 | +} | |
407 | +module_init(dynamic_printk_init); | |
408 | +/* may want to move this earlier so we can get traces as early as possible */ | |
409 | + | |
410 | +static int __init dynamic_printk_setup(char *str) | |
411 | +{ | |
412 | + if (str) | |
413 | + return -ENOENT; | |
414 | + set_all(true); | |
415 | + return 0; | |
416 | +} | |
417 | +/* Use early_param(), so we can get debug output as early as possible */ | |
418 | +early_param("dynamic_printk", dynamic_printk_setup); |
net/netfilter/nf_conntrack_pptp.c
... | ... | @@ -65,7 +65,7 @@ |
65 | 65 | struct nf_conntrack_expect *exp) __read_mostly; |
66 | 66 | EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn); |
67 | 67 | |
68 | -#ifdef DEBUG | |
68 | +#if defined(DEBUG) || defined(CONFIG_DYNAMIC_PRINTK_DEBUG) | |
69 | 69 | /* PptpControlMessageType names */ |
70 | 70 | const char *const pptp_msg_name[] = { |
71 | 71 | "UNKNOWN_MESSAGE", |
scripts/Makefile.lib
... | ... | @@ -96,6 +96,14 @@ |
96 | 96 | modname_flags = $(if $(filter 1,$(words $(modname))),\ |
97 | 97 | -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") |
98 | 98 | |
99 | +#hash values | |
100 | +ifdef CONFIG_DYNAMIC_PRINTK_DEBUG | |
101 | +debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\ | |
102 | + -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))" | |
103 | +else | |
104 | +debug_flags = | |
105 | +endif | |
106 | + | |
99 | 107 | orig_c_flags = $(KBUILD_CFLAGS) $(ccflags-y) $(CFLAGS_$(basetarget).o) |
100 | 108 | _c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags)) |
101 | 109 | _a_flags = $(KBUILD_AFLAGS) $(asflags-y) $(AFLAGS_$(basetarget).o) |
... | ... | @@ -121,7 +129,8 @@ |
121 | 129 | |
122 | 130 | c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \ |
123 | 131 | $(__c_flags) $(modkern_cflags) \ |
124 | - -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) | |
132 | + -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \ | |
133 | + $(debug_flags) | |
125 | 134 | |
126 | 135 | a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \ |
127 | 136 | $(__a_flags) $(modkern_aflags) |
scripts/basic/Makefile
... | ... | @@ -9,7 +9,7 @@ |
9 | 9 | # fixdep: Used to generate dependency information during build process |
10 | 10 | # docproc: Used in Documentation/DocBook |
11 | 11 | |
12 | -hostprogs-y := fixdep docproc | |
12 | +hostprogs-y := fixdep docproc hash | |
13 | 13 | always := $(hostprogs-y) |
14 | 14 | |
15 | 15 | # fixdep is needed to compile other host programs |
scripts/basic/hash.c
1 | +/* | |
2 | + * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com> | |
3 | + * | |
4 | + */ | |
5 | + | |
6 | +#include <stdio.h> | |
7 | +#include <stdlib.h> | |
8 | +#include <string.h> | |
9 | + | |
10 | +#define DYNAMIC_DEBUG_HASH_BITS 6 | |
11 | + | |
12 | +static const char *program; | |
13 | + | |
14 | +static void usage(void) | |
15 | +{ | |
16 | + printf("Usage: %s <djb2|r5> <modname>\n", program); | |
17 | + exit(1); | |
18 | +} | |
19 | + | |
20 | +/* djb2 hashing algorithm by Dan Bernstein. From: | |
21 | + * http://www.cse.yorku.ca/~oz/hash.html | |
22 | + */ | |
23 | + | |
24 | +unsigned int djb2_hash(char *str) | |
25 | +{ | |
26 | + unsigned long hash = 5381; | |
27 | + int c; | |
28 | + | |
29 | + c = *str; | |
30 | + while (c) { | |
31 | + hash = ((hash << 5) + hash) + c; | |
32 | + c = *++str; | |
33 | + } | |
34 | + return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1)); | |
35 | +} | |
36 | + | |
37 | +unsigned int r5_hash(char *str) | |
38 | +{ | |
39 | + unsigned long hash = 0; | |
40 | + int c; | |
41 | + | |
42 | + c = *str; | |
43 | + while (c) { | |
44 | + hash = (hash + (c << 4) + (c >> 4)) * 11; | |
45 | + c = *++str; | |
46 | + } | |
47 | + return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1)); | |
48 | +} | |
49 | + | |
50 | +int main(int argc, char *argv[]) | |
51 | +{ | |
52 | + program = argv[0]; | |
53 | + | |
54 | + if (argc != 3) | |
55 | + usage(); | |
56 | + if (!strcmp(argv[1], "djb2")) | |
57 | + printf("%d\n", djb2_hash(argv[2])); | |
58 | + else if (!strcmp(argv[1], "r5")) | |
59 | + printf("%d\n", r5_hash(argv[2])); | |
60 | + else | |
61 | + usage(); | |
62 | + exit(0); | |
63 | +} |