* [PATCH 1/7] dynamic debug v2 - infrastructure
@ 2008-07-15 21:31 Jason Baron
2008-07-17 7:01 ` Greg KH
2008-09-16 0:03 ` Rusty Russell
0 siblings, 2 replies; 29+ messages in thread
From: Jason Baron @ 2008-07-15 21:31 UTC (permalink / raw)
To: linux-kernel; +Cc: akpm, joe, greg, nick, randy.dunlap
-infrastructure patch
Signed-off-by: Jason Baron <jbaron@redhat.com>
---
Documentation/kernel-parameters.txt | 5
include/asm-generic/vmlinux.lds.h | 10 -
include/linux/device.h | 6
include/linux/dynamic_printk.h | 161 +++++++++
include/linux/kernel.h | 31 ++
include/linux/module.h | 4
kernel/module.c | 23 +
lib/Kconfig.debug | 79 +++++
lib/Makefile | 2
lib/dynamic_printk.c | 599 +++++++++++++++++++++++++++++++++++
net/netfilter/nf_conntrack_pptp.c | 2
scripts/Makefile.lib | 11 +
scripts/basic/Makefile | 2
scripts/basic/hash.c | 60 ++++
14 files changed, 986 insertions(+), 9 deletions(-)
create mode 100644 include/linux/dynamic_printk.h
create mode 100644 lib/dynamic_printk.c
create mode 100644 scripts/basic/hash.c
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index bf6303e..d9a1245 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1580,6 +1580,11 @@ and is between 256 and 4096 characters. It is defined in the file
autoconfiguration.
Ranges are in pairs (memory base and size).
+ dynamic_printk
+ Enables pr_debug()/dev_dbg() calls if
+ CONFIG_PRINK_DYNAMIC has been enabled. These can also
+ be switched on/off via <debugfs>/dynamic_printk/modules
+
print-fatal-signals=
[KNL] debug: print fatal signals
print-fatal-signals=1: print segfault info to
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index f054778..799a8b5 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -167,7 +167,6 @@
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
*(__ksymtab_strings) \
} \
- \
/* __*init sections */ \
__init_rodata : AT(ADDR(__init_rodata) - LOAD_OFFSET) { \
*(.ref.rodata) \
@@ -249,7 +248,14 @@
CPU_DISCARD(init.data) \
CPU_DISCARD(init.rodata) \
MEM_DISCARD(init.data) \
- MEM_DISCARD(init.rodata)
+ MEM_DISCARD(init.rodata) \
+ VMLINUX_SYMBOL(__start___verbose_strings) = .; \
+ *(__verbose_strings) \
+ VMLINUX_SYMBOL(__stop___verbose_strings) = .; \
+ . = ALIGN(8); \
+ VMLINUX_SYMBOL(__start___verbose) = .; \
+ *(__verbose) \
+ VMLINUX_SYMBOL(__stop___verbose) = .;
#define INIT_TEXT \
*(.init.text) \
diff --git a/include/linux/device.h b/include/linux/device.h
index 1a06026..fb03dbc 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -592,7 +592,11 @@ extern const char *dev_driver_string(struct device *dev);
#define dev_info(dev, format, arg...) \
dev_printk(KERN_INFO , dev , format , ## arg)
-#ifdef DEBUG
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#define dev_dbg(dev, format, ...) do { \
+ dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
+ } while (0)
+#elif defined(DEBUG)
#define dev_dbg(dev, format, arg...) \
dev_printk(KERN_DEBUG , dev , format , ## arg)
#else
diff --git a/include/linux/dynamic_printk.h b/include/linux/dynamic_printk.h
new file mode 100644
index 0000000..4ed0c14
--- /dev/null
+++ b/include/linux/dynamic_printk.h
@@ -0,0 +1,161 @@
+#ifndef _DYNAMIC_PRINTK_H
+#define _DYNAMIC_PRINTK_H
+
+#ifdef __KERNEL__
+
+#include <linux/string.h>
+#include <linux/hash.h>
+
+#define DYNAMIC_DEBUG_HASH_BITS 6
+#define DEBUG_HASH_TABLE_SIZE (1 << DYNAMIC_DEBUG_HASH_BITS)
+
+#define TYPE_BOOLEAN 0
+#define TYPE_LEVEL 1
+#define TYPE_FLAG 2
+
+#define DYNAMIC_ENABLED_ALL 0
+#define DYNAMIC_ENABLED_NONE 1
+#define DYNAMIC_ENABLED_SOME 2
+
+extern int dynamic_enabled;
+extern long long dynamic_printk_enabled;
+extern long long dynamic_printk_enabled2;
+
+struct mod_debug {
+ char *modname;
+ char *logical_modname;
+ char *type;
+ char *num_flags;
+ char *flag_names;
+} __attribute__((aligned(8)));
+
+static inline unsigned int dynamic_djb2_hash(char *str)
+{
+ unsigned long hash = 5381;
+ int c;
+
+ c = *str;
+ while (c) {
+ hash = ((hash << 5) + hash) + c;
+ c = *++str;
+ }
+ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
+}
+
+static inline unsigned int dynamic_r5_hash(char *str)
+{
+ unsigned long hash = 0;
+ int c;
+
+ c = *str;
+ while (c) {
+ hash = (hash + (c << 4) + (c >> 4)) * 11;
+ c = *++str;
+ }
+ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
+}
+
+int register_debug_module(char *mod_name, int type, char *share_name,
+ int num_flags, char *flags);
+
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+extern int unregister_debug_module(char *mod_name);
+int __dynamic_dbg_enabled_helper(char *modname, int type, int value, int level);
+
+#define __dynamic_dbg_enabled(module, type, value, level) ({ \
+ int ret = 0; \
+ if (dynamic_enabled == DYNAMIC_ENABLED_NONE) \
+ ret = 0; \
+ else if (dynamic_enabled == DYNAMIC_ENABLED_ALL) \
+ ret = 1; \
+ else { \
+ if ((dynamic_printk_enabled & (1LL << DEBUG_HASH)) && \
+ (dynamic_printk_enabled2 & (1LL << DEBUG_HASH2))) \
+ ret = __dynamic_dbg_enabled_helper(module, type, value,\
+ level);\
+ } \
+ ret; })
+
+#ifndef DYNAMIC_DEBUG_MODNAME
+#define DYNAMIC_DEBUG_MODNAME KBUILD_MODNAME
+#endif
+#ifndef DYNAMIC_DEBUG_NUM_FLAGS
+#define DYNAMIC_DEBUG_NUM_FLAGS "0"
+#endif
+#ifndef DYNAMIC_DEBUG_FLAG_NAMES
+#define DYNAMIC_DEBUG_FLAG_NAMES ""
+#endif
+#ifndef DYNAMIC_DEBUG_TYPE
+#define DYNAMIC_DEBUG_TYPE "0"
+#endif
+#define _dynamic_dbg_enabled(type, value, level) ({ \
+ int ret; \
+ static char mod_name[] \
+ __attribute__((section("__verbose_strings"))) \
+ = KBUILD_MODNAME; \
+ static char logical_mod_name[] \
+ __attribute__((section("__verbose_strings"))) \
+ = DYNAMIC_DEBUG_MODNAME; \
+ static char num_flags[] \
+ __attribute__((section("__verbose_strings"))) \
+ = DYNAMIC_DEBUG_NUM_FLAGS; \
+ static char flag_names[] \
+ __attribute__((section("__verbose_strings"))) \
+ = DYNAMIC_DEBUG_FLAG_NAMES; \
+ static char register_type[] \
+ __attribute__((section("__verbose_strings"))) \
+ = DYNAMIC_DEBUG_TYPE; \
+ static struct mod_debug descriptor \
+ __used \
+ __attribute__((section("__verbose"), aligned(8))) \
+ = { mod_name, logical_mod_name, register_type, num_flags, flag_names };\
+ ret = __dynamic_dbg_enabled(DYNAMIC_DEBUG_MODNAME, type, value, level);\
+ ret; })
+
+#define dynamic_pr_debug(fmt, ...) do { \
+ static char mod_name[] \
+ __attribute__((section("__verbose_strings"))) \
+ = KBUILD_MODNAME; \
+ static struct mod_debug descriptor \
+ __used \
+ __attribute__((section("__verbose"), aligned(8))) = \
+ { mod_name, mod_name, "0", "0", NULL }; \
+ if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, 0, 0)) \
+ printk(KERN_DEBUG KBUILD_MODNAME ":" fmt, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#define dynamic_dev_dbg(dev, format, ...) do { \
+ static char mod_name[] \
+ __attribute__((section("__verbose_strings"))) \
+ = KBUILD_MODNAME; \
+ static struct mod_debug descriptor \
+ __used \
+ __attribute__((section("__verbose"), aligned(8))) = \
+ { mod_name, mod_name, "0", "0", NULL }; \
+ if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, 0, 0)) \
+ dev_printk(KERN_DEBUG, dev, \
+ KBUILD_MODNAME ": " format, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#else
+
+static inline int unregister_debug_module(const char *mod_name)
+{
+ return 0;
+}
+static inline int __dynamic_dbg_enabled_helper(char *modname, int type,
+ int value, int level)
+{
+ return 0;
+}
+
+#define __dynamic_dbg_enabled(module, type, value, level) ({ 0; })
+#define _dynamic_dbg_enabled(type, value, level) ({ 0; })
+#define dynamic_pr_debug(fmt, ...) do { } while (0)
+#define dynamic_dev_dbg(dev, format, ...) do { } while (0)
+#endif
+
+#endif
+#endif
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index cd6d02c..3f99327 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -14,6 +14,7 @@
#include <linux/compiler.h>
#include <linux/bitops.h>
#include <linux/log2.h>
+#include <linux/dynamic_printk.h>
#include <asm/byteorder.h>
#include <asm/bug.h>
@@ -288,15 +289,39 @@ extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
#define pr_info(fmt, arg...) \
printk(KERN_INFO fmt, ##arg)
-#ifdef DEBUG
-/* If you are writing a driver, please use dev_dbg instead */
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#define pr_debug(fmt, ...) do { \
+ dynamic_pr_debug(fmt, ##__VA_ARGS__); \
+ } while (0)
+#elif defined(DEBUG)
#define pr_debug(fmt, arg...) \
- printk(KERN_DEBUG fmt, ##arg)
+ printk(KERN_DEBUG fmt, ##arg)
#else
#define pr_debug(fmt, arg...) \
({ if (0) printk(KERN_DEBUG fmt, ##arg); 0; })
#endif
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#define dynamic_dbg_enabled(call_type, value, level) ({ \
+ int ret = _dynamic_dbg_enabled(call_type, value, level);\
+ ret; })
+#elif defined(DEBUG)
+#define dynamic_dbg_enabled(type, value, level) do { \
+ if (type == TYPE_LEVEL) { \
+ if (value < level) \
+ return 1; \
+ } else if (type == TYPE_FLAG) { \
+ if (value & level) \
+ return 1; \
+ } else if (type == TYPE_BOOLEAN) \
+ return 1; \
+ return 0; \
+ } while (0)
+#else
+#define dynamic_dbg_enabled(type, value, level) \
+ ({ if (0) _dynamic_dbg_enabled(type, value, level); 0; })
+#endif
+
/*
* Display an IP address in readable format.
*/
diff --git a/include/linux/module.h b/include/linux/module.h
index 819c4e8..74a2e32 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -359,6 +359,10 @@ struct module
struct marker *markers;
unsigned int num_markers;
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ struct mod_debug *start_verbose;
+ unsigned int num_verbose;
+#endif
};
#ifndef MODULE_ARCH_INIT
#define MODULE_ARCH_INIT {}
diff --git a/kernel/module.c b/kernel/module.c
index 8d6cccc..5f36555 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -744,6 +744,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
}
/* Store the name of the last unloaded module for diagnostic purposes */
strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
+ unregister_debug_module(mod->name);
free_module(mod);
out:
@@ -1717,6 +1718,9 @@ static struct module *load_module(void __user *umod,
unsigned int unusedgplcrcindex;
unsigned int markersindex;
unsigned int markersstringsindex;
+ unsigned int verboseindex;
+ struct mod_debug *iter;
+ unsigned long value;
struct module *mod;
long err = 0;
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1993,6 +1997,7 @@ static struct module *load_module(void __user *umod,
markersindex = find_sec(hdr, sechdrs, secstrings, "__markers");
markersstringsindex = find_sec(hdr, sechdrs, secstrings,
"__markers_strings");
+ verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose");
/* Now do relocations. */
for (i = 1; i < hdr->e_shnum; i++) {
@@ -2020,6 +2025,11 @@ static struct module *load_module(void __user *umod,
mod->num_markers =
sechdrs[markersindex].sh_size / sizeof(*mod->markers);
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ mod->start_verbose = (void *)sechdrs[verboseindex].sh_addr;
+ mod->num_verbose = sechdrs[verboseindex].sh_size /
+ sizeof(*mod->start_verbose);
+#endif
/* Find duplicate symbols */
err = verify_export_symbols(mod);
@@ -2043,6 +2053,19 @@ static struct module *load_module(void __user *umod,
marker_update_probe_range(mod->markers,
mod->markers + mod->num_markers);
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ for (value = (unsigned long)mod->start_verbose;
+ value < (unsigned long)mod->start_verbose +
+ (unsigned long)(mod->num_verbose * sizeof(struct mod_debug));
+ value += sizeof(struct mod_debug)) {
+ iter = (struct mod_debug *)value;
+ register_debug_module(iter->modname,
+ simple_strtoul(iter->type, NULL, 10),
+ iter->logical_modname,
+ simple_strtoul(iter->num_flags, NULL, 10),
+ iter->flag_names);
+ }
+#endif
err = module_finalize(hdr, sechdrs, mod);
if (err < 0)
goto cleanup;
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 623ef24..6f8d76e 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -632,6 +632,85 @@ config FIREWIRE_OHCI_REMOTE_DMA
If unsure, say N.
+config DYNAMIC_PRINTK_DEBUG
+ bool "Enable dynamic printk() call support"
+ default n
+ depends on PRINTK
+ select PRINTK_DEBUG
+ help
+
+ Compiles debug level messages into the kernel, which would not
+ otherwise be available at runtime. These messages can then be
+ enabled/disabled on a per module basis. This mechanism, implicitly
+ enables all pr_debug() and dev_dbg() calls. It also introduces a
+ 'dynamic_dbg_enabled()' function which allows subsystems to implement
+ more complex dynamic debugging, including the use of per-subsystem
+ flags and and level controls. The impact of this compile option is a
+ larger kernel text size ~2%.
+
+ Usage:
+
+ Dynamic debugging is controlled by the debugfs file,
+ dynamic_printk/modules. This file contains a list of the modules that
+ can be enabled. The format of the file is the module name, followed
+ by a set of flags that can be enabled. The first flags is always the
+ 'enabled' flags. For example:
+
+ <module_name> <enabled=0/1> <level=[0-n]> <flag_name=0/1>....
+ <associated module names>
+ .
+ .
+ .
+
+ <module_name> : Name of the module in which the debug call resides
+ <enabled=0/1> : whether the the messages are enabled or not
+ <level=[0-n]> : For modules that support levels
+ <flag_name=0/1> : names of the flags that can be set
+ <associated module names> : names of the modules that are part of
+ group <module_name>
+
+ From a live system:
+
+ snd_hda_intel enabled=0
+
+ fixup enabled=0
+
+ cpufreq_shared enabled=0 CPUFREQ_DEBUG_CORE=0 CPUFREQ_DEBUG_DRIVER=0 CPUFREQ_DEBUG_GOVERNOR=0
+ acpi_cpufreq
+ freq_table
+ cpufreq_userspace
+ cpufreq_performance
+ cpufreq
+
+ driver enabled=0
+
+ dummy enabled=0
+
+ snd_seq 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
+
+ To set the level or flag value for type 'level' or 'flag':
+
+ $echo "set level=<#> <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 all
+ modules. This mode can be turned off by disabling modules.
+
source "samples/Kconfig"
source "lib/Kconfig.kgdb"
diff --git a/lib/Makefile b/lib/Makefile
index bf8000f..78ab656 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -70,6 +70,8 @@ lib-$(CONFIG_GENERIC_BUG) += bug.o
obj-$(CONFIG_HAVE_LMB) += lmb.o
+obj-$(CONFIG_DYNAMIC_PRINTK_DEBUG) += dynamic_printk.o
+
hostprogs-y := gen_crc32table
clean-files := crc32table.h
diff --git a/lib/dynamic_printk.c b/lib/dynamic_printk.c
new file mode 100644
index 0000000..326355d
--- /dev/null
+++ b/lib/dynamic_printk.c
@@ -0,0 +1,599 @@
+/*
+ * lib/dynamic_printk.c
+ *
+ * make pr_debug()/dev_dbg() calls runtime configurable based upon their
+ * their source module.
+ *
+ * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+
+#define SHARING_NONE 0
+#define SHARING_MEMBER 1
+#define SHARING_LEADER 2
+
+extern struct mod_debug __start___verbose[];
+extern struct mod_debug __stop___verbose[];
+
+char *type_to_string[3] = {
+ "boolean",
+ "level",
+ "flag",
+};
+
+struct flags_descriptor {
+ int num;
+ char **flag_names;
+};
+
+struct debug_name {
+ struct hlist_node hlist;
+ struct hlist_node hlist2;
+ int hash1;
+ int hash2;
+ char *name;
+ int enable;
+ int type;
+ int level;
+ int ratelimit;
+ struct flags_descriptor *flags;
+ /* for sharing between modules */
+ int type_sharing;
+ struct debug_name *parent;
+ struct list_head shared_list;
+ int count;
+};
+
+static int num_enabled;
+int dynamic_enabled = DYNAMIC_ENABLED_NONE;
+EXPORT_SYMBOL_GPL(dynamic_enabled);
+static struct hlist_head module_table[DEBUG_HASH_TABLE_SIZE] =
+ { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
+static struct hlist_head module_table2[DEBUG_HASH_TABLE_SIZE] =
+ { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
+static DECLARE_MUTEX(debug_list_mutex);
+static int nr_entries;
+
+long long dynamic_printk_enabled;
+EXPORT_SYMBOL_GPL(dynamic_printk_enabled);
+long long dynamic_printk_enabled2;
+EXPORT_SYMBOL_GPL(dynamic_printk_enabled2);
+
+/* returns the debug module pointer. caller must locking */
+static struct debug_name *find_debug_module(char *module_name)
+{
+ int found = 0;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *element;
+
+ element = NULL;
+ head = &module_table[dynamic_djb2_hash(module_name)];
+ hlist_for_each_entry_rcu(element, node, head, hlist) {
+ if (!strcmp(element->name, module_name)) {
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ return element;
+ return NULL;
+}
+
+/* caller must hold mutex*/
+static int __add_debug_module(char *mod_name)
+{
+ struct debug_name *new;
+ char *module_name;
+ int ret = 0;
+
+ if (find_debug_module(mod_name)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ module_name = kmalloc(strlen(mod_name) + 1, GFP_KERNEL);
+ if (!module_name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ module_name = strcpy(module_name, mod_name);
+ module_name[strlen(mod_name)] = '\0';
+ new = kzalloc(sizeof(struct debug_name), GFP_KERNEL);
+ if (!new) {
+ kfree(module_name);
+ ret = -ENOMEM;
+ goto out;
+ }
+ INIT_HLIST_NODE(&new->hlist);
+ INIT_HLIST_NODE(&new->hlist2);
+ INIT_LIST_HEAD(&new->shared_list);
+ new->name = module_name;
+ new->hash1 = dynamic_djb2_hash(new->name);
+ new->hash2 = dynamic_r5_hash(new->name);
+ hlist_add_head_rcu(&new->hlist,
+ &module_table[dynamic_djb2_hash(new->name)]);
+ hlist_add_head_rcu(&new->hlist2,
+ &module_table2[dynamic_r5_hash(new->name)]);
+ nr_entries++;
+out:
+ return ret;
+}
+
+int add_debug_module(char *mod_name)
+{
+ int ret;
+
+ down(&debug_list_mutex);
+ ret = __add_debug_module(mod_name);
+ up(&debug_list_mutex);
+ return ret;
+}
+
+int unregister_debug_module(char *mod_name)
+{
+ struct debug_name *element;
+ struct debug_name *parent = NULL;
+ int ret = 0;
+ int i;
+
+ down(&debug_list_mutex);
+ element = find_debug_module(mod_name);
+ if (!element) {
+ ret = -EINVAL;
+ goto out;
+ }
+ hlist_del_rcu(&element->hlist);
+ hlist_del_rcu(&element->hlist2);
+ if (element->type_sharing == SHARING_MEMBER) {
+ list_del_rcu(&element->shared_list);
+ element->parent->count -= 1;
+ if (element->parent->count == 0) {
+ parent = element->parent;
+ hlist_del_rcu(&parent->hlist);
+ hlist_del_rcu(&parent->hlist2);
+ }
+ }
+ synchronize_rcu();
+ if (element->name)
+ kfree(element->name);
+ if (element->flags) {
+ for (i = 0; i < element->flags->num; i++)
+ kfree(element->flags->flag_names[i]);
+ kfree(element->flags->flag_names);
+ kfree(element->flags);
+ }
+ if (element->enable)
+ num_enabled--;
+ kfree(element);
+ if (parent) {
+ kfree(parent->name);
+ if (parent->flags) {
+ for (i = 0; i < element->flags->num; i++)
+ kfree(element->flags->flag_names[i]);
+ kfree(parent->flags->flag_names);
+ kfree(parent->flags);
+ }
+ if (parent->enable)
+ num_enabled--;
+ kfree(parent);
+ nr_entries--;
+ }
+ nr_entries--;
+out:
+ up(&debug_list_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(unregister_debug_module);
+
+int register_debug_module(char *mod_name, int type, char *share_name,
+ int num_flags, char *flags)
+{
+ struct debug_name *elem, *parent;
+ char *flag;
+ int i;
+
+ down(&debug_list_mutex);
+ elem = find_debug_module(mod_name);
+ if (!elem) {
+ __add_debug_module(mod_name);
+ elem = find_debug_module(mod_name);
+ if (dynamic_enabled == DYNAMIC_ENABLED_ALL &&
+ !strcmp(mod_name, share_name)) {
+ elem->enable = true;
+ num_enabled++;
+ }
+ }
+ if (strcmp(mod_name, share_name)) {
+ parent = find_debug_module(share_name);
+ if (!parent) {
+ __add_debug_module(share_name);
+ parent = find_debug_module(share_name);
+ parent->type_sharing = SHARING_LEADER;
+ parent->type = type;
+ if (dynamic_enabled == DYNAMIC_ENABLED_ALL) {
+ parent->enable = true;
+ num_enabled++;
+ }
+ }
+ parent->count += 1;
+ elem->parent = parent;
+ elem->type_sharing = SHARING_MEMBER;
+ list_add_rcu(&elem->shared_list, &parent->shared_list);
+ } else
+ elem->type = type;
+ if (num_flags > 0) {
+ if ((elem->type_sharing == SHARING_MEMBER) && elem->parent)
+ elem = elem->parent;
+ elem->flags = kzalloc(sizeof(struct flags_descriptor),
+ GFP_KERNEL);
+ elem->flags->flag_names = kmalloc(sizeof(char *) * num_flags,
+ GFP_KERNEL);
+ for (i = 0; i < num_flags; i++) {
+ flag = strsep(&flags, ",");
+ elem->flags->flag_names[i] = kstrdup(flag, GFP_KERNEL);
+ }
+ smp_wmb();
+ elem->flags->num = num_flags;
+ }
+ up(&debug_list_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(register_debug_module);
+
+int __dynamic_dbg_enabled_helper(char *mod_name, int type, int value, int level)
+{
+ struct debug_name *elem;
+ int ret = 0;
+
+ rcu_read_lock();
+ elem = find_debug_module(mod_name);
+ if (elem) {
+ if ((elem->type_sharing == SHARING_MEMBER) && elem->parent)
+ elem = elem->parent;
+ if (elem->enable) {
+ if (elem->type == TYPE_LEVEL) {
+ if (value < elem->level)
+ ret = 1;
+ } else if (elem->type == TYPE_FLAG) {
+ if (value & elem->level)
+ ret = 1;
+ } else if (elem->type == TYPE_BOOLEAN)
+ ret = 1;
+ }
+ }
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__dynamic_dbg_enabled_helper);
+
+static void set_all(bool enable)
+{
+ struct debug_name *e;
+ struct hlist_node *node;
+ int i;
+ long long enable_mask;
+
+ for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
+ if (module_table[i].first != NULL) {
+ hlist_for_each_entry(e, node, &module_table[i], hlist) {
+ e->enable = enable;
+ }
+ }
+ }
+ if (enable)
+ enable_mask = ULLONG_MAX;
+ else
+ enable_mask = 0;
+ dynamic_printk_enabled = enable_mask;
+ dynamic_printk_enabled2 = enable_mask;
+}
+
+static int disabled_hash(int i)
+{
+ struct debug_name *e;
+ struct hlist_node *node;
+
+ hlist_for_each_entry(e, node, &module_table[i], hlist) {
+ if (e->enable)
+ return 0;
+ }
+ return 1;
+}
+
+static int disabled_hash2(int i)
+{
+ struct debug_name *e;
+ struct hlist_node *node;
+
+ hlist_for_each_entry(e, node, &module_table2[i], hlist2) {
+ if (e->enable)
+ return 0;
+ }
+ return 1;
+}
+
+static void set_children(bool enable, struct debug_name *parent)
+{
+ struct list_head *p;
+ struct debug_name *elem_shared;
+
+ if (parent->type_sharing == SHARING_LEADER) {
+ list_for_each_rcu(p, &parent->shared_list) {
+ elem_shared =
+ list_entry(p, struct debug_name, shared_list);
+ elem_shared->enable = enable;
+ if (enable) {
+ dynamic_printk_enabled |=
+ (1LL << elem_shared->hash1);
+ dynamic_printk_enabled2 |=
+ (1LL << elem_shared->hash2);
+ } else {
+ if (disabled_hash(elem_shared->hash1))
+ dynamic_printk_enabled |=
+ ~(1LL << elem_shared->hash1);
+ if (disabled_hash2(elem_shared->hash2))
+ dynamic_printk_enabled2 |=
+ ~(1LL << elem_shared->hash2);
+ }
+ }
+ }
+}
+
+static ssize_t pr_debug_write(struct file *file, const char __user *buf,
+ size_t length, loff_t *ppos)
+{
+ char *buffer, *s, *level, *value_str, *setting_str;
+ int err, hash, value, j;
+ struct debug_name *elem;
+ int all = 0;
+
+ if (length > PAGE_SIZE || length < 0)
+ return -EINVAL;
+
+ buffer = (char *)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ err = -EFAULT;
+ if (copy_from_user(buffer, buf, length))
+ goto out;
+
+ err = -EINVAL;
+ if (length < PAGE_SIZE)
+ buffer[length] = '\0';
+ else if (buffer[PAGE_SIZE-1])
+ goto out;
+
+ err = -EINVAL;
+ down(&debug_list_mutex);
+
+ if (strncmp("set", buffer, 3))
+ goto out_up;
+ s = buffer + 3;
+ setting_str = strsep(&s, "=");
+ if (s == NULL)
+ goto out_up;
+ setting_str = strstrip(setting_str);
+ value_str = strsep(&s, " ");
+ if (s == NULL)
+ goto out_up;
+ s = strstrip(s);
+ if (!strncmp(s, "all", 3))
+ all = 1;
+ else
+ elem = find_debug_module(s);
+ if (!strncmp(setting_str, "enable", 6)) {
+ value = !!simple_strtol(value_str, NULL, 10);
+ if (all) {
+ if (value) {
+ set_all(true);
+ num_enabled = nr_entries;
+ dynamic_enabled = DYNAMIC_ENABLED_ALL;
+ } else {
+ set_all(false);
+ num_enabled = 0;
+ dynamic_enabled = DYNAMIC_ENABLED_NONE;
+ }
+ err = 0;
+ } else {
+ if (elem && (elem->type_sharing != SHARING_MEMBER)) {
+ if (value && (elem->enable == 0)) {
+ hash = dynamic_djb2_hash(s);
+ dynamic_printk_enabled |=
+ (1LL << hash);
+ hash = dynamic_r5_hash(s);
+ dynamic_printk_enabled2 |=
+ (1LL << hash);
+ elem->enable = 1;
+ num_enabled++;
+ dynamic_enabled = DYNAMIC_ENABLED_SOME;
+ set_children(true, elem);
+ err = 0;
+ } else if (!value && (elem->enable == 1)) {
+ elem->enable = 0;
+ num_enabled--;
+ hash = dynamic_djb2_hash(s);
+ if (disabled_hash(hash))
+ dynamic_printk_enabled |=
+ ~(1LL << hash);
+ hash = dynamic_r5_hash(s);
+ if (disabled_hash2(hash))
+ dynamic_printk_enabled2 |=
+ ~(1LL << hash);
+ if (num_enabled)
+ dynamic_enabled =
+ DYNAMIC_ENABLED_SOME;
+ else
+ dynamic_enabled =
+ DYNAMIC_ENABLED_NONE;
+ set_children(false, elem);
+ err = 0;
+ }
+ }
+ }
+ } else if (!strncmp(setting_str, "level", 5)) {
+ elem = find_debug_module(s);
+ if (elem && (elem->type_sharing != SHARING_MEMBER)) {
+ if (elem->type == TYPE_LEVEL) {
+ elem->level =
+ simple_strtol(value_str, NULL, 10);
+ err = 0;
+ }
+ }
+ } else {
+ elem = find_debug_module(s);
+ if (elem && (elem->type_sharing != SHARING_MEMBER)) {
+ if ((elem->type == TYPE_FLAG) && elem->flags) {
+ value = !!simple_strtol(value_str, NULL, 10);
+ for (j = 0; j < elem->flags->num; j++) {
+ if (!strcmp(elem->flags->flag_names[j],
+ setting_str)) {
+ if (strstr(setting_str, "ALL")){
+ if (value)
+ elem->level =
+ UINT_MAX;
+ else
+ elem->level = 0;
+ } else {
+ if (value)
+ elem->level |=
+ (1 << j);
+ else
+ elem->level |=
+ ~(1 << j);
+ }
+ err = 0;
+ }
+ }
+ }
+ }
+ }
+ if (!err)
+ err = length;
+out_up:
+ up(&debug_list_mutex);
+out:
+ free_page((unsigned long)buffer);
+ return err;
+}
+
+static void *pr_debug_seq_start(struct seq_file *f, loff_t *pos)
+{
+ return (*pos < DEBUG_HASH_TABLE_SIZE) ? pos : NULL;
+}
+
+static void *pr_debug_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ (*pos)++;
+ if (*pos >= DEBUG_HASH_TABLE_SIZE)
+ return NULL;
+ return pos;
+}
+
+static void pr_debug_seq_stop(struct seq_file *s, void *v)
+{
+ /* Nothing to do */
+}
+
+static int pr_debug_seq_show(struct seq_file *s, void *v)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *elem, *elem_shared;
+ struct list_head *p;
+ unsigned int i = *(loff_t *) v;
+ int j;
+
+ rcu_read_lock();
+ head = &module_table[i];
+ hlist_for_each_entry_rcu(elem, node, head, hlist) {
+ if (elem->type_sharing == SHARING_MEMBER)
+ continue;
+ seq_printf(s, "%s enabled=%d", elem->name, elem->enable);
+ if (elem->type == TYPE_LEVEL)
+ seq_printf(" level=%d", elem->level);
+ if ((elem->type == TYPE_FLAG) && elem->flags) {
+ for (j = 0; j < elem->flags->num; j++)
+ seq_printf(s, " %s=%d",
+ elem->flags->flag_names[j],
+ ((elem->level >> j) & 1));
+ }
+ seq_printf(s, "\n");
+ if (elem->type_sharing == SHARING_LEADER) {
+ list_for_each_rcu(p, &elem->shared_list) {
+ elem_shared = list_entry(p, struct debug_name,
+ shared_list);
+ seq_printf(s, "\t%s\n", elem_shared->name);
+ }
+ }
+ seq_printf(s, "\n");
+ }
+ rcu_read_unlock();
+ return 0;
+}
+
+static struct seq_operations pr_debug_seq_ops = {
+ .start = pr_debug_seq_start,
+ .next = pr_debug_seq_next,
+ .stop = pr_debug_seq_stop,
+ .show = pr_debug_seq_show
+};
+
+static int pr_debug_open(struct inode *inode, struct file *filp)
+{
+ return seq_open(filp, &pr_debug_seq_ops);
+}
+
+static const struct file_operations pr_debug_operations = {
+ .open = pr_debug_open,
+ .read = seq_read,
+ .write = pr_debug_write,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+int __init dynamic_printk_init(void)
+{
+ struct dentry *dir, *file;
+ struct mod_debug *iter;
+ unsigned long value;
+
+ dir = debugfs_create_dir("dynamic_printk", NULL);
+ if (!dir)
+ return -ENOMEM;
+ file = debugfs_create_file("modules", 0644, dir, NULL,
+ &pr_debug_operations);
+ if (!file) {
+ debugfs_remove(dir);
+ return -ENOMEM;
+ }
+ for (value = (unsigned long)__start___verbose;
+ value < (unsigned long)__stop___verbose;
+ value += sizeof(struct mod_debug)) {
+ iter = (struct mod_debug *)value;
+ register_debug_module(iter->modname,
+ simple_strtoul(iter->type, NULL, 10),
+ iter->logical_modname,
+ simple_strtoul(iter->num_flags, NULL, 10),
+ iter->flag_names);
+ }
+ return 0;
+}
+module_init(dynamic_printk_init);
+/* may want to move this earlier so we can get traces as early as possible */
+
+static int __init dynamic_printk_setup(char *str)
+{
+ if (str)
+ return -ENOENT;
+ set_all(true);
+ return 0;
+}
+/* Use early_param(), so we can get debug output as early as possible */
+early_param("dynamic_printk", dynamic_printk_setup);
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index 97e54b0..7fea304 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -65,7 +65,7 @@ void
struct nf_conntrack_expect *exp) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn);
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
/* PptpControlMessageType names */
const char *const pptp_msg_name[] = {
"UNKNOWN_MESSAGE",
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 8e44023..bb635ae 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -96,6 +96,14 @@ basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
modname_flags = $(if $(filter 1,$(words $(modname))),\
-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+#hash values
+ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+hash_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(modname))" \
+ -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(modname))"
+else
+hash_flags =
+endif
+
_c_flags = $(KBUILD_CFLAGS) $(ccflags-y) $(CFLAGS_$(basetarget).o)
_a_flags = $(KBUILD_AFLAGS) $(asflags-y) $(AFLAGS_$(basetarget).o)
_cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F))
@@ -120,7 +128,8 @@ endif
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
$(__c_flags) $(modkern_cflags) \
- -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+ -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \
+ $(hash_flags)
a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
$(__a_flags) $(modkern_aflags)
diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile
index 4c324a1..0955995 100644
--- a/scripts/basic/Makefile
+++ b/scripts/basic/Makefile
@@ -9,7 +9,7 @@
# fixdep: Used to generate dependency information during build process
# docproc: Used in Documentation/DocBook
-hostprogs-y := fixdep docproc
+hostprogs-y := fixdep docproc hash
always := $(hostprogs-y)
# fixdep is needed to compile other host programs
diff --git a/scripts/basic/hash.c b/scripts/basic/hash.c
new file mode 100644
index 0000000..8025d4b
--- /dev/null
+++ b/scripts/basic/hash.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define DYNAMIC_DEBUG_HASH_BITS 6
+
+static const char *program;
+
+static void usage(void)
+{
+ printf("Usage: %s <djb2|r5> <modname>\n", program);
+ exit(1);
+}
+
+unsigned int djb2_hash(char *str)
+{
+ unsigned long hash = 5381;
+ int c;
+
+ c = *str;
+ while (c) {
+ hash = ((hash << 5) + hash) + c;
+ c = *++str;
+ }
+ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
+}
+
+unsigned int r5_hash(char *str)
+{
+ unsigned long hash = 0;
+ int c;
+
+ c = *str;
+ while (c) {
+ hash = (hash + (c << 4) + (c >> 4)) * 11;
+ c = *++str;
+ }
+ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
+}
+
+int main(int argc, char *argv[])
+{
+ program = argv[0];
+
+ if (argc != 3)
+ usage();
+ if (!strcmp(argv[1], "djb2"))
+ printf("%d\n", djb2_hash(argv[2]));
+ else if (!strcmp(argv[1], "r5"))
+ printf("%d\n", r5_hash(argv[2]));
+ else
+ usage();
+ exit(0);
+}
+
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-07-15 21:31 [PATCH 1/7] dynamic debug v2 - infrastructure Jason Baron
@ 2008-07-17 7:01 ` Greg KH
2008-07-17 21:20 ` Jason Baron
2008-09-16 0:03 ` Rusty Russell
1 sibling, 1 reply; 29+ messages in thread
From: Greg KH @ 2008-07-17 7:01 UTC (permalink / raw)
To: Jason Baron; +Cc: linux-kernel, akpm, joe, nick, randy.dunlap
On Tue, Jul 15, 2008 at 05:31:08PM -0400, Jason Baron wrote:
> diff --git a/include/linux/device.h b/include/linux/device.h
> index 1a06026..fb03dbc 100644
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -592,7 +592,11 @@ extern const char *dev_driver_string(struct device *dev);
> #define dev_info(dev, format, arg...) \
> dev_printk(KERN_INFO , dev , format , ## arg)
>
> -#ifdef DEBUG
> +#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
> +#define dev_dbg(dev, format, ...) do { \
> + dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
> + } while (0)
> +#elif defined(DEBUG)
> #define dev_dbg(dev, format, arg...) \
> dev_printk(KERN_DEBUG , dev , format , ## arg)
> #else
In looking at your follow-on patches, where you add this to subsystems,
it seems that you have to add a lot of #include <linux/dynamic_printk.h>
lines.
And in looking at this modification to device.h, I think lots of the
kernel should break, but you are getting it "for free" by including the
.h file within kernel.h.
Why not also include it here in device.h?
Also, with this change, code that is already using dev_dbg() today is
instantly converted over to this logic now, right?
Anyway, this looks great, no objections from me at all, very good work.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-07-17 7:01 ` Greg KH
@ 2008-07-17 21:20 ` Jason Baron
2008-07-17 22:32 ` Greg KH
0 siblings, 1 reply; 29+ messages in thread
From: Jason Baron @ 2008-07-17 21:20 UTC (permalink / raw)
To: Greg KH; +Cc: linux-kernel, akpm, joe, nick, randy.dunlap
On Thu, Jul 17, 2008 at 12:01:03AM -0700, Greg KH wrote:
> Return-Path: <greg@kroah.com>
> On Tue, Jul 15, 2008 at 05:31:08PM -0400, Jason Baron wrote:
> > diff --git a/include/linux/device.h b/include/linux/device.h
> > index 1a06026..fb03dbc 100644
> > --- a/include/linux/device.h
> > +++ b/include/linux/device.h
> > @@ -592,7 +592,11 @@ extern const char *dev_driver_string(struct device *dev);
> > #define dev_info(dev, format, arg...) \
> > dev_printk(KERN_INFO , dev , format , ## arg)
> >
> > -#ifdef DEBUG
> > +#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
> > +#define dev_dbg(dev, format, ...) do { \
> > + dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
> > + } while (0)
> > +#elif defined(DEBUG)
> > #define dev_dbg(dev, format, arg...) \
> > dev_printk(KERN_DEBUG , dev , format , ## arg)
> > #else
>
> In looking at your follow-on patches, where you add this to subsystems,
> it seems that you have to add a lot of #include <linux/dynamic_printk.h>
> lines.
>
> And in looking at this modification to device.h, I think lots of the
> kernel should break, but you are getting it "for free" by including the
> .h file within kernel.h.
>
> Why not also include it here in device.h?
>
I don't believe the follow-on patches include "<linux/dynamic_printk.h>".
However, some of them do include a subsystem specific #include. For example,
the cpufreq subsystem include, <linux/dynamic_debug_cpufreq.h>:
+++ b/include/linux/dynamic_debug_cpufreq.h
@@ -0,0 +1,8 @@
+#define DYNAMIC_DEBUG_NUM_FLAGS "3"
+#define DYNAMIC_DEBUG_FLAG_NAMES "CPUFREQ_DEBUG_CORE,CPUFREQ_DEBUG_DRIVER,CPUFREQ_DEBUG_GOVERNOR"
+#define DYNAMIC_DEBUG_TYPE "2"
+#define DYNAMIC_DEBUG_MODNAME "cpufreq_shared"
+
+#ifdef CONFIG_CPU_FREQ_DEBUG
+#define DEBUG 1
+#endif
This header file conveys that cpufreq subsystem, wants non-default options-it
has 3 debugging flags that can be set, and all modules in the subsystem are
tied together using the module name: "cpufreq_shared".
I don't have an explicit #include of kernel.h in device.h b/c it already picked
up.
> Also, with this change, code that is already using dev_dbg() today is
> instantly converted over to this logic now, right?
>
that is correct. any callers of dev_dbg() don't have to do anything. its really
only the more complex debugging, where there are flags or levels that need to
make adjustments to work with the new infrastructure.
thanks,
-Jason
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-07-17 21:20 ` Jason Baron
@ 2008-07-17 22:32 ` Greg KH
2008-07-17 22:56 ` Dominik Brodowski
` (2 more replies)
0 siblings, 3 replies; 29+ messages in thread
From: Greg KH @ 2008-07-17 22:32 UTC (permalink / raw)
To: Jason Baron; +Cc: linux-kernel, akpm, joe, nick, randy.dunlap
On Thu, Jul 17, 2008 at 05:20:40PM -0400, Jason Baron wrote:
> On Thu, Jul 17, 2008 at 12:01:03AM -0700, Greg KH wrote:
> > Return-Path: <greg@kroah.com>
> > On Tue, Jul 15, 2008 at 05:31:08PM -0400, Jason Baron wrote:
> > > diff --git a/include/linux/device.h b/include/linux/device.h
> > > index 1a06026..fb03dbc 100644
> > > --- a/include/linux/device.h
> > > +++ b/include/linux/device.h
> > > @@ -592,7 +592,11 @@ extern const char *dev_driver_string(struct device *dev);
> > > #define dev_info(dev, format, arg...) \
> > > dev_printk(KERN_INFO , dev , format , ## arg)
> > >
> > > -#ifdef DEBUG
> > > +#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
> > > +#define dev_dbg(dev, format, ...) do { \
> > > + dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
> > > + } while (0)
> > > +#elif defined(DEBUG)
> > > #define dev_dbg(dev, format, arg...) \
> > > dev_printk(KERN_DEBUG , dev , format , ## arg)
> > > #else
> >
> > In looking at your follow-on patches, where you add this to subsystems,
> > it seems that you have to add a lot of #include <linux/dynamic_printk.h>
> > lines.
> >
> > And in looking at this modification to device.h, I think lots of the
> > kernel should break, but you are getting it "for free" by including the
> > .h file within kernel.h.
> >
> > Why not also include it here in device.h?
> >
>
> I don't believe the follow-on patches include "<linux/dynamic_printk.h>".
> However, some of them do include a subsystem specific #include. For example,
> the cpufreq subsystem include, <linux/dynamic_debug_cpufreq.h>:
Ah, you are correct, sorry about that, I misread.
> +++ b/include/linux/dynamic_debug_cpufreq.h
> @@ -0,0 +1,8 @@
> +#define DYNAMIC_DEBUG_NUM_FLAGS "3"
> +#define DYNAMIC_DEBUG_FLAG_NAMES "CPUFREQ_DEBUG_CORE,CPUFREQ_DEBUG_DRIVER,CPUFREQ_DEBUG_GOVERNOR"
> +#define DYNAMIC_DEBUG_TYPE "2"
> +#define DYNAMIC_DEBUG_MODNAME "cpufreq_shared"
> +
> +#ifdef CONFIG_CPU_FREQ_DEBUG
> +#define DEBUG 1
> +#endif
>
> This header file conveys that cpufreq subsystem, wants non-default options-it
> has 3 debugging flags that can be set, and all modules in the subsystem are
> tied together using the module name: "cpufreq_shared".
>
> I don't have an explicit #include of kernel.h in device.h b/c it already picked
> up.
>
> > Also, with this change, code that is already using dev_dbg() today is
> > instantly converted over to this logic now, right?
> >
>
> that is correct. any callers of dev_dbg() don't have to do anything. its really
> only the more complex debugging, where there are flags or levels that need to
> make adjustments to work with the new infrastructure.
For this reason alone, I see no reason why your patch should not be
merged today. You don't need the other subsystems at this point in time
in my opinion, it's benifit is huge already.
Not to say that you shouldn't also go after these subsystems in your
overall scheme here, but please, don't feel it should hold your code up
at this point in time :)
Because of that, do you want me to try to merge the basic infrastructure
and dev_dbg() support through the driver-core tree? This code has been
in the past -mm and linux-next releases, right?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-07-17 22:32 ` Greg KH
@ 2008-07-17 22:56 ` Dominik Brodowski
2008-07-17 23:35 ` Greg KH
2008-07-18 14:39 ` Jason Baron
2008-08-08 21:51 ` Jason Baron
2 siblings, 1 reply; 29+ messages in thread
From: Dominik Brodowski @ 2008-07-17 22:56 UTC (permalink / raw)
To: Greg KH; +Cc: Jason Baron, linux-kernel, akpm, joe, nick, randy.dunlap
Hi,
On Thu, Jul 17, 2008 at 03:32:22PM -0700, Greg KH wrote:
> > that is correct. any callers of dev_dbg() don't have to do anything. its really
> > only the more complex debugging, where there are flags or levels that need to
> > make adjustments to work with the new infrastructure.
>
> For this reason alone, I see no reason why your patch should not be
> merged today. You don't need the other subsystems at this point in time
> in my opinion, it's benifit is huge already.
not to object to this statement, but:
what about the user-visible interface? currently, it's based around one big
debugfs file. What about doing
<debugfs>/dynamic_printk/<module_name>/{enabled[,level][,flag][,modules]}
instead, or even
<sysfs>/module/<module_name>/debug/{enabled[,level][,flag]}
For "shared" modules like cpufreq (only user so far, AFAICS), things might
get a bit more interesting, but we found that out already in the other
thread ;)
Best wishes,
Dominik
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-07-17 22:56 ` Dominik Brodowski
@ 2008-07-17 23:35 ` Greg KH
2008-07-18 6:37 ` Dominik Brodowski
0 siblings, 1 reply; 29+ messages in thread
From: Greg KH @ 2008-07-17 23:35 UTC (permalink / raw)
To: Dominik Brodowski, Jason Baron, linux-kernel, akpm, joe, nick,
randy.dunlap
On Fri, Jul 18, 2008 at 12:56:11AM +0200, Dominik Brodowski wrote:
> Hi,
>
> On Thu, Jul 17, 2008 at 03:32:22PM -0700, Greg KH wrote:
> > > that is correct. any callers of dev_dbg() don't have to do anything. its really
> > > only the more complex debugging, where there are flags or levels that need to
> > > make adjustments to work with the new infrastructure.
> >
> > For this reason alone, I see no reason why your patch should not be
> > merged today. You don't need the other subsystems at this point in time
> > in my opinion, it's benifit is huge already.
>
> not to object to this statement, but:
>
> what about the user-visible interface? currently, it's based around one big
> debugfs file. What about doing
>
> <debugfs>/dynamic_printk/<module_name>/{enabled[,level][,flag][,modules]}
By virtue of this being in debugfs, we can change the user interface
around as time goes on if we want to with no ill side affects. :)
> instead, or even
>
> <sysfs>/module/<module_name>/debug/{enabled[,level][,flag]}
I like this as that is what a number of current modules do (usb-serial
drivers), but you have to be careful about the module parameter
namespace to not get collisions here with existing "debug" files.
So for now, I recommend staying in debugfs, it makes more sense.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-07-17 23:35 ` Greg KH
@ 2008-07-18 6:37 ` Dominik Brodowski
0 siblings, 0 replies; 29+ messages in thread
From: Dominik Brodowski @ 2008-07-18 6:37 UTC (permalink / raw)
To: Greg KH; +Cc: Jason Baron, linux-kernel, akpm, joe, nick, randy.dunlap
On Thu, Jul 17, 2008 at 04:35:24PM -0700, Greg KH wrote:
> > <sysfs>/module/<module_name>/debug/{enabled[,level][,flag]}
>
> I like this as that is what a number of current modules do (usb-serial
> drivers), but you have to be careful about the module parameter
> namespace to not get collisions here with existing "debug" files.
That's why I'd put it into a different namespace (debug instead of
parameters).
> So for now, I recommend staying in debugfs, it makes more sense.
ACK.
Best,
Dominik
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-07-17 22:32 ` Greg KH
2008-07-17 22:56 ` Dominik Brodowski
@ 2008-07-18 14:39 ` Jason Baron
2008-08-08 21:51 ` Jason Baron
2 siblings, 0 replies; 29+ messages in thread
From: Jason Baron @ 2008-07-18 14:39 UTC (permalink / raw)
To: Greg KH; +Cc: linux-kernel, akpm, joe, nick, randy.dunlap
On Thu, Jul 17, 2008 at 03:32:22PM -0700, Greg KH wrote:
> On Thu, Jul 17, 2008 at 05:20:40PM -0400, Jason Baron wrote:
> > On Thu, Jul 17, 2008 at 12:01:03AM -0700, Greg KH wrote:
> > > Return-Path: <greg@kroah.com>
> > > On Tue, Jul 15, 2008 at 05:31:08PM -0400, Jason Baron wrote:
> > > > diff --git a/include/linux/device.h b/include/linux/device.h
> > > > index 1a06026..fb03dbc 100644
> > > > --- a/include/linux/device.h
> > > > +++ b/include/linux/device.h
> > > > @@ -592,7 +592,11 @@ extern const char *dev_driver_string(struct device *dev);
> > > > #define dev_info(dev, format, arg...) \
> > > > dev_printk(KERN_INFO , dev , format , ## arg)
> > > >
> > > > -#ifdef DEBUG
> > > > +#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
> > > > +#define dev_dbg(dev, format, ...) do { \
> > > > + dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
> > > > + } while (0)
> > > > +#elif defined(DEBUG)
> > > > #define dev_dbg(dev, format, arg...) \
> > > > dev_printk(KERN_DEBUG , dev , format , ## arg)
> > > > #else
> > >
> > > In looking at your follow-on patches, where you add this to subsystems,
> > > it seems that you have to add a lot of #include <linux/dynamic_printk.h>
> > > lines.
> > >
> > > And in looking at this modification to device.h, I think lots of the
> > > kernel should break, but you are getting it "for free" by including the
> > > .h file within kernel.h.
> > >
> > > Why not also include it here in device.h?
> > >
> >
> > I don't believe the follow-on patches include "<linux/dynamic_printk.h>".
> > However, some of them do include a subsystem specific #include. For example,
> > the cpufreq subsystem include, <linux/dynamic_debug_cpufreq.h>:
>
> Ah, you are correct, sorry about that, I misread.
>
> > +++ b/include/linux/dynamic_debug_cpufreq.h
> > @@ -0,0 +1,8 @@
> > +#define DYNAMIC_DEBUG_NUM_FLAGS "3"
> > +#define DYNAMIC_DEBUG_FLAG_NAMES "CPUFREQ_DEBUG_CORE,CPUFREQ_DEBUG_DRIVER,CPUFREQ_DEBUG_GOVERNOR"
> > +#define DYNAMIC_DEBUG_TYPE "2"
> > +#define DYNAMIC_DEBUG_MODNAME "cpufreq_shared"
> > +
> > +#ifdef CONFIG_CPU_FREQ_DEBUG
> > +#define DEBUG 1
> > +#endif
> >
> > This header file conveys that cpufreq subsystem, wants non-default options-it
> > has 3 debugging flags that can be set, and all modules in the subsystem are
> > tied together using the module name: "cpufreq_shared".
> >
> > I don't have an explicit #include of kernel.h in device.h b/c it already picked
> > up.
> >
> > > Also, with this change, code that is already using dev_dbg() today is
> > > instantly converted over to this logic now, right?
> > >
> >
> > that is correct. any callers of dev_dbg() don't have to do anything. its really
> > only the more complex debugging, where there are flags or levels that need to
> > make adjustments to work with the new infrastructure.
>
> For this reason alone, I see no reason why your patch should not be
> merged today. You don't need the other subsystems at this point in time
> in my opinion, it's benifit is huge already.
>
> Not to say that you shouldn't also go after these subsystems in your
> overall scheme here, but please, don't feel it should hold your code up
> at this point in time :)
>
> Because of that, do you want me to try to merge the basic infrastructure
> and dev_dbg() support through the driver-core tree? This code has been
> in the past -mm and linux-next releases, right?
>
On my system, with just the pr_debug, dev_dbg() hooks, i get about 80 modules
loaded that i can enable/disable debugging for. So, this piece is useful by
itself as you point out.
However, there are a couple important issues that need to be resolved. One is
the the infrastructure relies on 'KBUILD_MODNAME' to differentiate modules.
However, these are not necessarily unique within the tree. For example,
mm/mmap.c and arch/x86/mm/mmap.c both have the 'KBUILD_MODNAME' of 'mmap'.
Thus, enabling debugging for one of these will enabled both. Perhaps, this
is the desired affect, but there might be cases where we want to differentiate?
We could use a combination of directory location in combination with
'KBUILD_MODNAME'.
The second issue, is the splitting up the control file from one monolithic one,
to one per module...i did one monolithic one to make the implementation simpler
but we could definitely split it up.
So, yes it could go in now, or I can try and polish it a little more...it has
not yet had a runtime in either -mm or linux-next yet.
thanks,
-Jason
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-07-17 22:32 ` Greg KH
2008-07-17 22:56 ` Dominik Brodowski
2008-07-18 14:39 ` Jason Baron
@ 2008-08-08 21:51 ` Jason Baron
2008-08-09 1:07 ` Greg KH
2008-08-09 2:38 ` Randy Dunlap
2 siblings, 2 replies; 29+ messages in thread
From: Jason Baron @ 2008-08-08 21:51 UTC (permalink / raw)
To: Greg KH; +Cc: linux-kernel, akpm, joe, nick, randy.dunlap
On Thu, Jul 17, 2008 at 03:32:22PM -0700, Greg KH wrote:
> >
> > > Also, with this change, code that is already using dev_dbg() today is
> > > instantly converted over to this logic now, right?
> > >
> >
> > that is correct. any callers of dev_dbg() don't have to do anything. its really
> > only the more complex debugging, where there are flags or levels that need to
> > make adjustments to work with the new infrastructure.
>
> For this reason alone, I see no reason why your patch should not be
> merged today. You don't need the other subsystems at this point in time
> in my opinion, it's benifit is huge already.
>
> Not to say that you shouldn't also go after these subsystems in your
> overall scheme here, but please, don't feel it should hold your code up
> at this point in time :)
>
> Because of that, do you want me to try to merge the basic infrastructure
> and dev_dbg() support through the driver-core tree? This code has been
> in the past -mm and linux-next releases, right?
>
ok, here's a patch that implements just the basic core functionality that ties
into pr_debug() and dev_dbg(). That is, any users of those two functions can
be dynamically enabled/disabled at runtime if CONFIG_DYNAMIC_PRINTK_DEBUG is
set at compile time. We can add the more complex flag/level debugging later as
you suggest...
Few notes...there is still one control file: <debugfs>/dynamic_printk/modules
We can split this up now or later, but I kind of like being able to see all
the controls in one file. Also, i've used a djb2 hash function in the code,
which i'm not sure is under the correct license/copyright, so i just wanted
to point that out as well. see: scripts/basic/hash.c. If its an issue, i can
find another hash function.
thanks,
-Jason
Signed-off-by: Jason Baron <jbaron@redhat.com>
---
Documentation/kernel-parameters.txt | 5
include/asm-generic/vmlinux.lds.h | 10 +
include/linux/device.h | 6 -
include/linux/dynamic_printk.h | 94 ++++++++
include/linux/kernel.h | 7 +
include/linux/module.h | 4
kernel/module.c | 22 ++
lib/Kconfig.debug | 56 +++++
lib/Makefile | 2
lib/dynamic_printk.c | 409 +++++++++++++++++++++++++++++++++++
net/netfilter/nf_conntrack_pptp.c | 2
scripts/Makefile.lib | 11 +
scripts/basic/Makefile | 2
scripts/basic/hash.c | 64 +++++
14 files changed, 688 insertions(+), 6 deletions(-)
create mode 100644 include/linux/dynamic_printk.h
create mode 100644 lib/dynamic_printk.c
create mode 100644 scripts/basic/hash.c
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index bf6303e..7c60e89 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1580,6 +1580,11 @@ and is between 256 and 4096 characters. It is defined in the file
autoconfiguration.
Ranges are in pairs (memory base and size).
+ dynamic_printk
+ Enables pr_debug()/dev_dbg() calls if
+ CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled. These can also
+ be switched on/off via <debugfs>/dynamic_printk/modules
+
print-fatal-signals=
[KNL] debug: print fatal signals
print-fatal-signals=1: print segfault info to
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index f054778..00804e0 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -249,7 +249,15 @@
CPU_DISCARD(init.data) \
CPU_DISCARD(init.rodata) \
MEM_DISCARD(init.data) \
- MEM_DISCARD(init.rodata)
+ MEM_DISCARD(init.rodata) \
+ /* implement dynamic printk debug */ \
+ VMLINUX_SYMBOL(__start___verbose_strings) = .; \
+ *(__verbose_strings) \
+ VMLINUX_SYMBOL(__stop___verbose_strings) = .; \
+ . = ALIGN(8); \
+ VMLINUX_SYMBOL(__start___verbose) = .; \
+ *(__verbose) \
+ VMLINUX_SYMBOL(__stop___verbose) = .;
#define INIT_TEXT \
*(.init.text) \
diff --git a/include/linux/device.h b/include/linux/device.h
index 1a06026..fb03dbc 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -592,7 +592,11 @@ extern const char *dev_driver_string(struct device *dev);
#define dev_info(dev, format, arg...) \
dev_printk(KERN_INFO , dev , format , ## arg)
-#ifdef DEBUG
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#define dev_dbg(dev, format, ...) do { \
+ dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
+ } while (0)
+#elif defined(DEBUG)
#define dev_dbg(dev, format, arg...) \
dev_printk(KERN_DEBUG , dev , format , ## arg)
#else
diff --git a/include/linux/dynamic_printk.h b/include/linux/dynamic_printk.h
new file mode 100644
index 0000000..8377929
--- /dev/null
+++ b/include/linux/dynamic_printk.h
@@ -0,0 +1,94 @@
+#ifndef _DYNAMIC_PRINTK_H
+#define _DYNAMIC_PRINTK_H
+
+#ifdef __KERNEL__
+
+#include <linux/string.h>
+#include <linux/hash.h>
+
+#define DYNAMIC_DEBUG_HASH_BITS 6
+#define DEBUG_HASH_TABLE_SIZE (1 << DYNAMIC_DEBUG_HASH_BITS)
+
+#define TYPE_BOOLEAN 1
+
+#define DYNAMIC_ENABLED_ALL 0
+#define DYNAMIC_ENABLED_NONE 1
+#define DYNAMIC_ENABLED_SOME 2
+
+extern int dynamic_enabled;
+extern long long dynamic_printk_enabled;
+extern long long dynamic_printk_enabled2;
+
+struct mod_debug {
+ char *modname;
+ char *logical_modname;
+ char *flag_names;
+ int type;
+ int hash;
+ int hash2;
+} __attribute__((aligned(8)));
+
+int register_dynamic_debug_module(char *mod_name, int type, char *share_name,
+ char *flags, int hash, int hash2);
+
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+extern int unregister_dynamic_debug_module(char *mod_name);
+extern int __dynamic_dbg_enabled_helper(char *modname, int type,
+ int value, int hash);
+
+#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ \
+ int ret = 0; \
+ if (unlikely((dynamic_printk_enabled & (1LL << DEBUG_HASH)) && \
+ (dynamic_printk_enabled2 & (1LL << DEBUG_HASH2)))) \
+ ret = __dynamic_dbg_enabled_helper(module, type, \
+ value, hash);\
+ ret; })
+
+#define dynamic_pr_debug(fmt, ...) do { \
+ static char mod_name[] \
+ __attribute__((section("__verbose_strings"))) \
+ = KBUILD_MODNAME; \
+ static struct mod_debug descriptor \
+ __used \
+ __attribute__((section("__verbose"), aligned(8))) = \
+ { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\
+ if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \
+ 0, 0, DEBUG_HASH)) \
+ printk(KERN_DEBUG KBUILD_MODNAME ":" fmt, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#define dynamic_dev_dbg(dev, format, ...) do { \
+ static char mod_name[] \
+ __attribute__((section("__verbose_strings"))) \
+ = KBUILD_MODNAME; \
+ static struct mod_debug descriptor \
+ __used \
+ __attribute__((section("__verbose"), aligned(8))) = \
+ { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\
+ if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \
+ 0, 0, DEBUG_HASH)) \
+ dev_printk(KERN_DEBUG, dev, \
+ KBUILD_MODNAME ": " format, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#else
+
+static inline int unregister_dynamic_debug_module(const char *mod_name)
+{
+ return 0;
+}
+static inline int __dynamic_dbg_enabled_helper(char *modname, int type,
+ int value, int hash)
+{
+ return 0;
+}
+
+#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ 0; })
+#define dynamic_pr_debug(fmt, ...) do { } while (0)
+#define dynamic_dev_dbg(dev, format, ...) do { } while (0)
+#endif
+
+#endif
+#endif
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index cd6d02c..25d09b8 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -14,6 +14,7 @@
#include <linux/compiler.h>
#include <linux/bitops.h>
#include <linux/log2.h>
+#include <linux/dynamic_printk.h>
#include <asm/byteorder.h>
#include <asm/bug.h>
@@ -288,8 +289,12 @@ extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
#define pr_info(fmt, arg...) \
printk(KERN_INFO fmt, ##arg)
-#ifdef DEBUG
/* If you are writing a driver, please use dev_dbg instead */
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#define pr_debug(fmt, ...) do { \
+ dynamic_pr_debug(fmt, ##__VA_ARGS__); \
+ } while (0)
+#elif defined(DEBUG)
#define pr_debug(fmt, arg...) \
printk(KERN_DEBUG fmt, ##arg)
#else
diff --git a/include/linux/module.h b/include/linux/module.h
index 819c4e8..74a2e32 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -359,6 +359,10 @@ struct module
struct marker *markers;
unsigned int num_markers;
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ struct mod_debug *start_verbose;
+ unsigned int num_verbose;
+#endif
};
#ifndef MODULE_ARCH_INIT
#define MODULE_ARCH_INIT {}
diff --git a/kernel/module.c b/kernel/module.c
index 8d6cccc..ad7a105 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -744,6 +744,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
}
/* Store the name of the last unloaded module for diagnostic purposes */
strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
+ unregister_dynamic_debug_module(mod->name);
free_module(mod);
out:
@@ -1717,6 +1718,9 @@ static struct module *load_module(void __user *umod,
unsigned int unusedgplcrcindex;
unsigned int markersindex;
unsigned int markersstringsindex;
+ unsigned int verboseindex;
+ struct mod_debug *iter;
+ unsigned long value;
struct module *mod;
long err = 0;
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1993,6 +1997,7 @@ static struct module *load_module(void __user *umod,
markersindex = find_sec(hdr, sechdrs, secstrings, "__markers");
markersstringsindex = find_sec(hdr, sechdrs, secstrings,
"__markers_strings");
+ verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose");
/* Now do relocations. */
for (i = 1; i < hdr->e_shnum; i++) {
@@ -2020,6 +2025,11 @@ static struct module *load_module(void __user *umod,
mod->num_markers =
sechdrs[markersindex].sh_size / sizeof(*mod->markers);
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ mod->start_verbose = (void *)sechdrs[verboseindex].sh_addr;
+ mod->num_verbose = sechdrs[verboseindex].sh_size /
+ sizeof(*mod->start_verbose);
+#endif
/* Find duplicate symbols */
err = verify_export_symbols(mod);
@@ -2043,6 +2053,18 @@ static struct module *load_module(void __user *umod,
marker_update_probe_range(mod->markers,
mod->markers + mod->num_markers);
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ for (value = (unsigned long)mod->start_verbose;
+ value < (unsigned long)mod->start_verbose +
+ (unsigned long)(mod->num_verbose * sizeof(struct mod_debug));
+ value += sizeof(struct mod_debug)) {
+ iter = (struct mod_debug *)value;
+ register_dynamic_debug_module(iter->modname,
+ iter->type,
+ iter->logical_modname,
+ iter->flag_names, iter->hash, iter->hash2);
+ }
+#endif
err = module_finalize(hdr, sechdrs, mod);
if (err < 0)
goto cleanup;
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 623ef24..6664783 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -632,6 +632,62 @@ config FIREWIRE_OHCI_REMOTE_DMA
If unsure, say N.
+config DYNAMIC_PRINTK_DEBUG
+ bool "Enable dynamic printk() call support"
+ default n
+ depends on PRINTK
+ select PRINTK_DEBUG
+ help
+
+ Compiles debug level messages into the kernel, which would not
+ otherwise be available at runtime. These messages can then be
+ enabled/disabled on a per module basis. This mechanism, implicitly
+ enables all pr_debug() and dev_dbg() calls. The impact of this
+ compile option is a larger kernel text size ~2%.
+
+ Usage:
+
+ Dynamic debugging is controlled by the debugfs file,
+ dynamic_printk/modules. This file contains a list of the modules that
+ can be enabled. The format of the file is the module name, followed
+ by a set of flags that can be enabled. The first flags is always the
+ 'enabled' flags. For example:
+
+ <module_name> <enabled=0/1>
+ .
+ .
+ .
+
+ <module_name> : Name of the module in which the debug call resides
+ <enabled=0/1> : whether the the messages are enabled or not
+
+ From a live system:
+
+ snd_hda_intel enabled=0
+
+ fixup enabled=0
+
+ 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 all
+ modules. This mode can be turned off by disabling modules.
+
source "samples/Kconfig"
source "lib/Kconfig.kgdb"
diff --git a/lib/Makefile b/lib/Makefile
index bf8000f..78ab656 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -70,6 +70,8 @@ lib-$(CONFIG_GENERIC_BUG) += bug.o
obj-$(CONFIG_HAVE_LMB) += lmb.o
+obj-$(CONFIG_DYNAMIC_PRINTK_DEBUG) += dynamic_printk.o
+
hostprogs-y := gen_crc32table
clean-files := crc32table.h
diff --git a/lib/dynamic_printk.c b/lib/dynamic_printk.c
new file mode 100644
index 0000000..04ae7e2
--- /dev/null
+++ b/lib/dynamic_printk.c
@@ -0,0 +1,409 @@
+/*
+ * lib/dynamic_printk.c
+ *
+ * make pr_debug()/dev_dbg() calls runtime configurable based upon their
+ * their source module.
+ *
+ * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+
+extern struct mod_debug __start___verbose[];
+extern struct mod_debug __stop___verbose[];
+
+struct debug_name {
+ struct hlist_node hlist;
+ struct hlist_node hlist2;
+ int hash1;
+ int hash2;
+ char *name;
+ int enable;
+ int type;
+};
+
+static int nr_entries;
+static int num_enabled;
+int dynamic_enabled = DYNAMIC_ENABLED_NONE;
+static struct hlist_head module_table[DEBUG_HASH_TABLE_SIZE] =
+ { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
+static struct hlist_head module_table2[DEBUG_HASH_TABLE_SIZE] =
+ { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
+static DECLARE_MUTEX(debug_list_mutex);
+
+long long dynamic_printk_enabled;
+EXPORT_SYMBOL_GPL(dynamic_printk_enabled);
+long long dynamic_printk_enabled2;
+EXPORT_SYMBOL_GPL(dynamic_printk_enabled2);
+
+/* returns the debug module pointer. caller must locking */
+static struct debug_name *find_debug_module(char *module_name)
+{
+ int i;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *element;
+
+ element = NULL;
+ for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
+ head = &module_table[i];
+ hlist_for_each_entry_rcu(element, node, head, hlist)
+ if (!strcmp(element->name, module_name))
+ return element;
+ }
+ return NULL;
+}
+
+/* returns the debug module pointer. caller must locking */
+static struct debug_name *find_debug_module_hash(char *module_name, int hash)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *element;
+
+ element = NULL;
+ head = &module_table[hash];
+ hlist_for_each_entry_rcu(element, node, head, hlist)
+ if (!strcmp(element->name, module_name))
+ return element;
+ return NULL;
+}
+
+/* caller must hold mutex*/
+static int __add_debug_module(char *mod_name, int hash, int hash2)
+{
+ struct debug_name *new;
+ char *module_name;
+ int ret = 0;
+
+ if (find_debug_module(mod_name)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ module_name = kmalloc(strlen(mod_name) + 1, GFP_KERNEL);
+ if (!module_name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ module_name = strcpy(module_name, mod_name);
+ module_name[strlen(mod_name)] = '\0';
+ new = kzalloc(sizeof(struct debug_name), GFP_KERNEL);
+ if (!new) {
+ kfree(module_name);
+ ret = -ENOMEM;
+ goto out;
+ }
+ INIT_HLIST_NODE(&new->hlist);
+ INIT_HLIST_NODE(&new->hlist2);
+ new->name = module_name;
+ new->hash1 = hash;
+ new->hash2 = hash2;
+ hlist_add_head_rcu(&new->hlist, &module_table[hash]);
+ hlist_add_head_rcu(&new->hlist2, &module_table2[hash2]);
+ nr_entries++;
+out:
+ return ret;
+}
+
+int unregister_dynamic_debug_module(char *mod_name)
+{
+ struct debug_name *element;
+ int ret = 0;
+
+ down(&debug_list_mutex);
+ element = find_debug_module(mod_name);
+ if (!element) {
+ ret = -EINVAL;
+ goto out;
+ }
+ hlist_del_rcu(&element->hlist);
+ hlist_del_rcu(&element->hlist2);
+ synchronize_rcu();
+ if (element->name)
+ kfree(element->name);
+ if (element->enable)
+ num_enabled--;
+ kfree(element);
+ nr_entries--;
+out:
+ up(&debug_list_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(unregister_dynamic_debug_module);
+
+int register_dynamic_debug_module(char *mod_name, int type, char *share_name,
+ char *flags, int hash, int hash2)
+{
+ struct debug_name *elem;
+ int ret = 0;
+
+ down(&debug_list_mutex);
+ elem = find_debug_module(mod_name);
+ if (!elem) {
+ if (__add_debug_module(mod_name, hash, hash2))
+ goto out;
+ elem = find_debug_module(mod_name);
+ if (dynamic_enabled == DYNAMIC_ENABLED_ALL &&
+ !strcmp(mod_name, share_name)) {
+ elem->enable = true;
+ num_enabled++;
+ }
+ }
+ elem->type |= type;
+out:
+ up(&debug_list_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_dynamic_debug_module);
+
+int __dynamic_dbg_enabled_helper(char *mod_name, int type, int value, int hash)
+{
+ struct debug_name *elem;
+ int ret = 0;
+
+ if (dynamic_enabled == DYNAMIC_ENABLED_ALL)
+ return 1;
+ rcu_read_lock();
+ elem = find_debug_module_hash(mod_name, hash);
+ if (elem && elem->enable)
+ ret = 1;
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__dynamic_dbg_enabled_helper);
+
+static void set_all(bool enable)
+{
+ struct debug_name *e;
+ struct hlist_node *node;
+ int i;
+ long long enable_mask;
+
+ for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
+ if (module_table[i].first != NULL) {
+ hlist_for_each_entry(e, node, &module_table[i], hlist) {
+ e->enable = enable;
+ }
+ }
+ }
+ if (enable)
+ enable_mask = ULLONG_MAX;
+ else
+ enable_mask = 0;
+ dynamic_printk_enabled = enable_mask;
+ dynamic_printk_enabled2 = enable_mask;
+}
+
+static int disabled_hash(int i, bool first_table)
+{
+ struct debug_name *e;
+ struct hlist_node *node;
+
+ if (first_table) {
+ hlist_for_each_entry(e, node, &module_table[i], hlist) {
+ if (e->enable)
+ return 0;
+ }
+ } else {
+ hlist_for_each_entry(e, node, &module_table2[i], hlist2) {
+ if (e->enable)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static ssize_t pr_debug_write(struct file *file, const char __user *buf,
+ size_t length, loff_t *ppos)
+{
+ char *buffer, *s, *value_str, *setting_str;
+ int err, value;
+ struct debug_name *elem = NULL;
+ int all = 0;
+
+ if (length > PAGE_SIZE || length < 0)
+ return -EINVAL;
+
+ buffer = (char *)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ err = -EFAULT;
+ if (copy_from_user(buffer, buf, length))
+ goto out;
+
+ err = -EINVAL;
+ if (length < PAGE_SIZE)
+ buffer[length] = '\0';
+ else if (buffer[PAGE_SIZE-1])
+ goto out;
+
+ err = -EINVAL;
+ down(&debug_list_mutex);
+
+ if (strncmp("set", buffer, 3))
+ goto out_up;
+ s = buffer + 3;
+ setting_str = strsep(&s, "=");
+ if (s == NULL)
+ goto out_up;
+ setting_str = strstrip(setting_str);
+ value_str = strsep(&s, " ");
+ if (s == NULL)
+ goto out_up;
+ s = strstrip(s);
+ if (!strncmp(s, "all", 3))
+ all = 1;
+ else
+ elem = find_debug_module(s);
+ if (!strncmp(setting_str, "enable", 6)) {
+ value = !!simple_strtol(value_str, NULL, 10);
+ if (all) {
+ if (value) {
+ set_all(true);
+ num_enabled = nr_entries;
+ dynamic_enabled = DYNAMIC_ENABLED_ALL;
+ } else {
+ set_all(false);
+ num_enabled = 0;
+ dynamic_enabled = DYNAMIC_ENABLED_NONE;
+ }
+ err = 0;
+ } else {
+ if (elem) {
+ if (value && (elem->enable == 0)) {
+ dynamic_printk_enabled |=
+ (1LL << elem->hash1);
+ dynamic_printk_enabled2 |=
+ (1LL << elem->hash2);
+ elem->enable = 1;
+ num_enabled++;
+ dynamic_enabled = DYNAMIC_ENABLED_SOME;
+ err = 0;
+ } else if (!value && (elem->enable == 1)) {
+ elem->enable = 0;
+ num_enabled--;
+ if (disabled_hash(elem->hash1, true))
+ dynamic_printk_enabled &=
+ ~(1LL << elem->hash1);
+ if (disabled_hash(elem->hash2, false))
+ dynamic_printk_enabled2 &=
+ ~(1LL << elem->hash2);
+ if (num_enabled)
+ dynamic_enabled =
+ DYNAMIC_ENABLED_SOME;
+ else
+ dynamic_enabled =
+ DYNAMIC_ENABLED_NONE;
+ err = 0;
+ }
+ }
+ }
+ }
+ if (!err)
+ err = length;
+out_up:
+ up(&debug_list_mutex);
+out:
+ free_page((unsigned long)buffer);
+ return err;
+}
+
+static void *pr_debug_seq_start(struct seq_file *f, loff_t *pos)
+{
+ return (*pos < DEBUG_HASH_TABLE_SIZE) ? pos : NULL;
+}
+
+static void *pr_debug_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ (*pos)++;
+ if (*pos >= DEBUG_HASH_TABLE_SIZE)
+ return NULL;
+ return pos;
+}
+
+static void pr_debug_seq_stop(struct seq_file *s, void *v)
+{
+ /* Nothing to do */
+}
+
+static int pr_debug_seq_show(struct seq_file *s, void *v)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *elem;
+ unsigned int i = *(loff_t *) v;
+
+ rcu_read_lock();
+ head = &module_table[i];
+ hlist_for_each_entry_rcu(elem, node, head, hlist) {
+ seq_printf(s, "%s enabled=%d", elem->name, elem->enable);
+ seq_printf(s, "\n");
+ }
+ rcu_read_unlock();
+ return 0;
+}
+
+static struct seq_operations pr_debug_seq_ops = {
+ .start = pr_debug_seq_start,
+ .next = pr_debug_seq_next,
+ .stop = pr_debug_seq_stop,
+ .show = pr_debug_seq_show
+};
+
+static int pr_debug_open(struct inode *inode, struct file *filp)
+{
+ return seq_open(filp, &pr_debug_seq_ops);
+}
+
+static const struct file_operations pr_debug_operations = {
+ .open = pr_debug_open,
+ .read = seq_read,
+ .write = pr_debug_write,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+int __init dynamic_printk_init(void)
+{
+ struct dentry *dir, *file;
+ struct mod_debug *iter;
+ unsigned long value;
+
+ dir = debugfs_create_dir("dynamic_printk", NULL);
+ if (!dir)
+ return -ENOMEM;
+ file = debugfs_create_file("modules", 0644, dir, NULL,
+ &pr_debug_operations);
+ if (!file) {
+ debugfs_remove(dir);
+ return -ENOMEM;
+ }
+ for (value = (unsigned long)__start___verbose;
+ value < (unsigned long)__stop___verbose;
+ value += sizeof(struct mod_debug)) {
+ iter = (struct mod_debug *)value;
+ register_dynamic_debug_module(iter->modname,
+ iter->type,
+ iter->logical_modname,
+ iter->flag_names, iter->hash, iter->hash2);
+ }
+ return 0;
+}
+module_init(dynamic_printk_init);
+/* may want to move this earlier so we can get traces as early as possible */
+
+static int __init dynamic_printk_setup(char *str)
+{
+ if (str)
+ return -ENOENT;
+ set_all(true);
+ return 0;
+}
+/* Use early_param(), so we can get debug output as early as possible */
+early_param("dynamic_printk", dynamic_printk_setup);
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index 97e54b0..7fea304 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -65,7 +65,7 @@ void
struct nf_conntrack_expect *exp) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn);
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
/* PptpControlMessageType names */
const char *const pptp_msg_name[] = {
"UNKNOWN_MESSAGE",
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 8e44023..1e393cf 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -96,6 +96,14 @@ basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
modname_flags = $(if $(filter 1,$(words $(modname))),\
-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+#hash values
+ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\
+ -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))"
+else
+debug_flags =
+endif
+
_c_flags = $(KBUILD_CFLAGS) $(ccflags-y) $(CFLAGS_$(basetarget).o)
_a_flags = $(KBUILD_AFLAGS) $(asflags-y) $(AFLAGS_$(basetarget).o)
_cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F))
@@ -120,7 +128,8 @@ endif
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
$(__c_flags) $(modkern_cflags) \
- -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+ -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \
+ $(debug_flags)
a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
$(__a_flags) $(modkern_aflags)
diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile
index 4c324a1..0955995 100644
--- a/scripts/basic/Makefile
+++ b/scripts/basic/Makefile
@@ -9,7 +9,7 @@
# fixdep: Used to generate dependency information during build process
# docproc: Used in Documentation/DocBook
-hostprogs-y := fixdep docproc
+hostprogs-y := fixdep docproc hash
always := $(hostprogs-y)
# fixdep is needed to compile other host programs
diff --git a/scripts/basic/hash.c b/scripts/basic/hash.c
new file mode 100644
index 0000000..3299ad7
--- /dev/null
+++ b/scripts/basic/hash.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define DYNAMIC_DEBUG_HASH_BITS 6
+
+static const char *program;
+
+static void usage(void)
+{
+ printf("Usage: %s <djb2|r5> <modname>\n", program);
+ exit(1);
+}
+
+/* djb2 hashing algorithm by Dan Bernstein. From:
+ * http://www.cse.yorku.ca/~oz/hash.html
+ */
+
+unsigned int djb2_hash(char *str)
+{
+ unsigned long hash = 5381;
+ int c;
+
+ c = *str;
+ while (c) {
+ hash = ((hash << 5) + hash) + c;
+ c = *++str;
+ }
+ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
+}
+
+unsigned int r5_hash(char *str)
+{
+ unsigned long hash = 0;
+ int c;
+
+ c = *str;
+ while (c) {
+ hash = (hash + (c << 4) + (c >> 4)) * 11;
+ c = *++str;
+ }
+ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
+}
+
+int main(int argc, char *argv[])
+{
+ program = argv[0];
+
+ if (argc != 3)
+ usage();
+ if (!strcmp(argv[1], "djb2"))
+ printf("%d\n", djb2_hash(argv[2]));
+ else if (!strcmp(argv[1], "r5"))
+ printf("%d\n", r5_hash(argv[2]));
+ else
+ usage();
+ exit(0);
+}
+
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-08 21:51 ` Jason Baron
@ 2008-08-09 1:07 ` Greg KH
2008-08-11 14:12 ` Jason Baron
2008-08-09 2:38 ` Randy Dunlap
1 sibling, 1 reply; 29+ messages in thread
From: Greg KH @ 2008-08-09 1:07 UTC (permalink / raw)
To: Jason Baron; +Cc: linux-kernel, akpm, joe, nick, randy.dunlap
On Fri, Aug 08, 2008 at 05:51:53PM -0400, Jason Baron wrote:
>
> ok, here's a patch that implements just the basic core functionality that ties
> into pr_debug() and dev_dbg(). That is, any users of those two functions can
> be dynamically enabled/disabled at runtime if CONFIG_DYNAMIC_PRINTK_DEBUG is
> set at compile time. We can add the more complex flag/level debugging later as
> you suggest...
Very nice, just as I'm writing patches to dynamically make
CONFIG_USB_DEBUG be selectable on the fly :)
Don't worry, that can easily be moved over to your version once it is
done and in the tree...
> Few notes...there is still one control file: <debugfs>/dynamic_printk/modules
> We can split this up now or later, but I kind of like being able to see all
> the controls in one file. Also, i've used a djb2 hash function in the code,
> which i'm not sure is under the correct license/copyright, so i just wanted
> to point that out as well. see: scripts/basic/hash.c. If its an issue, i can
> find another hash function.
Why use that hash function? Actually, it looks like you are using 2
different ones, right? Why?
> --- /dev/null
> +++ b/include/linux/dynamic_printk.h
> @@ -0,0 +1,94 @@
> +#ifndef _DYNAMIC_PRINTK_H
> +#define _DYNAMIC_PRINTK_H
> +
> +#ifdef __KERNEL__
Shouldn't be needed.
> +#include <linux/string.h>
> +#include <linux/hash.h>
> +
> +#define DYNAMIC_DEBUG_HASH_BITS 6
> +#define DEBUG_HASH_TABLE_SIZE (1 << DYNAMIC_DEBUG_HASH_BITS)
> +
> +#define TYPE_BOOLEAN 1
What's this for?
> +#define DYNAMIC_ENABLED_ALL 0
> +#define DYNAMIC_ENABLED_NONE 1
> +#define DYNAMIC_ENABLED_SOME 2
> +
> +extern int dynamic_enabled;
> +extern long long dynamic_printk_enabled;
> +extern long long dynamic_printk_enabled2;
What's up with the "2" versions?
> +config DYNAMIC_PRINTK_DEBUG
> + bool "Enable dynamic printk() call support"
> + default n
> + depends on PRINTK
> + select PRINTK_DEBUG
> + help
> +
> + Compiles debug level messages into the kernel, which would not
> + otherwise be available at runtime. These messages can then be
> + enabled/disabled on a per module basis. This mechanism, implicitly
> + enables all pr_debug() and dev_dbg() calls. The impact of this
> + compile option is a larger kernel text size ~2%.
Trailing spaces :(
It's looking very good so far.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-08 21:51 ` Jason Baron
2008-08-09 1:07 ` Greg KH
@ 2008-08-09 2:38 ` Randy Dunlap
2008-08-11 17:36 ` Jason Baron
1 sibling, 1 reply; 29+ messages in thread
From: Randy Dunlap @ 2008-08-09 2:38 UTC (permalink / raw)
To: Jason Baron; +Cc: Greg KH, linux-kernel, akpm, joe, nick
On Fri, 8 Aug 2008 17:51:53 -0400 Jason Baron wrote:
> Few notes...there is still one control file: <debugfs>/dynamic_printk/modules
> We can split this up now or later, but I kind of like being able to see all
> the controls in one file. Also, i've used a djb2 hash function in the code,
> which i'm not sure is under the correct license/copyright, so i just wanted
> to point that out as well. see: scripts/basic/hash.c. If its an issue, i can
> find another hash function.
What license does it have? I don't see one.
> ---
>
> Documentation/kernel-parameters.txt | 5
> include/asm-generic/vmlinux.lds.h | 10 +
> include/linux/device.h | 6 -
> include/linux/dynamic_printk.h | 94 ++++++++
> include/linux/kernel.h | 7 +
> include/linux/module.h | 4
> kernel/module.c | 22 ++
> lib/Kconfig.debug | 56 +++++
> lib/Makefile | 2
> lib/dynamic_printk.c | 409 +++++++++++++++++++++++++++++++++++
> net/netfilter/nf_conntrack_pptp.c | 2
> scripts/Makefile.lib | 11 +
> scripts/basic/Makefile | 2
> scripts/basic/hash.c | 64 +++++
> 14 files changed, 688 insertions(+), 6 deletions(-)
> create mode 100644 include/linux/dynamic_printk.h
> create mode 100644 lib/dynamic_printk.c
> create mode 100644 scripts/basic/hash.c
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index 623ef24..6664783 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -632,6 +632,62 @@ config FIREWIRE_OHCI_REMOTE_DMA
>
> If unsure, say N.
>
> +config DYNAMIC_PRINTK_DEBUG
> + bool "Enable dynamic printk() call support"
> + default n
> + depends on PRINTK
> + select PRINTK_DEBUG
> + help
> +
> + Compiles debug level messages into the kernel, which would not
> + otherwise be available at runtime. These messages can then be
> + enabled/disabled on a per module basis. This mechanism, implicitly
no comma. Don't end lines with whitespace.
> + enables all pr_debug() and dev_dbg() calls. The impact of this
> + compile option is a larger kernel text size ~2%.
size of about 2%.
> +
> + Usage:
> +
> + Dynamic debugging is controlled by the debugfs file,
> + dynamic_printk/modules. This file contains a list of the modules that
> + can be enabled. The format of the file is the module name, followed
> + by a set of flags that can be enabled. The first flags is always the
first flag is
> + 'enabled' flags. For example:
flag.
> +
> + <module_name> <enabled=0/1>
> + .
> + .
> + .
> +
> + <module_name> : Name of the module in which the debug call resides
> + <enabled=0/1> : whether the the messages are enabled or not
the
> +
> + From a live system:
> +
> + snd_hda_intel enabled=0
> +
> + fixup enabled=0
> +
> + driver enabled=0
including the apparently extraneous blank lines??
> +
> + 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 all
> + modules. This mode can be turned off by disabling modules.
What does "can be turned off by disabling modules" mean, please?
CONFIG_MODULES=n or something else?
> +
> source "samples/Kconfig"
>
> source "lib/Kconfig.kgdb"
> diff --git a/lib/dynamic_printk.c b/lib/dynamic_printk.c
> new file mode 100644
> index 0000000..04ae7e2
> --- /dev/null
> +++ b/lib/dynamic_printk.c
> @@ -0,0 +1,409 @@
> +
> +extern struct mod_debug __start___verbose[];
> +extern struct mod_debug __stop___verbose[];
put these into a header file.
> +
> +struct debug_name {
> + struct hlist_node hlist;
> + struct hlist_node hlist2;
> + int hash1;
> + int hash2;
> + char *name;
> + int enable;
> + int type;
> +};
> +
> +static int nr_entries;
> +static int num_enabled;
> +int dynamic_enabled = DYNAMIC_ENABLED_NONE;
> +static struct hlist_head module_table[DEBUG_HASH_TABLE_SIZE] =
> + { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
> +static struct hlist_head module_table2[DEBUG_HASH_TABLE_SIZE] =
> + { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
> +static DECLARE_MUTEX(debug_list_mutex);
> +
> +long long dynamic_printk_enabled;
> +EXPORT_SYMBOL_GPL(dynamic_printk_enabled);
> +long long dynamic_printk_enabled2;
> +EXPORT_SYMBOL_GPL(dynamic_printk_enabled2);
> +
> +/* returns the debug module pointer. caller must locking */
caller must ___ locking ??
> +static struct debug_name *find_debug_module(char *module_name)
> +{
> + int i;
> + struct hlist_head *head;
> + struct hlist_node *node;
> + struct debug_name *element;
> +
> + element = NULL;
> + for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
> + head = &module_table[i];
> + hlist_for_each_entry_rcu(element, node, head, hlist)
> + if (!strcmp(element->name, module_name))
> + return element;
> + }
> + return NULL;
> +}
> +
> +/* returns the debug module pointer. caller must locking */
ditto, check comment.
> +static struct debug_name *find_debug_module_hash(char *module_name, int hash)
> +{
> + struct hlist_head *head;
> + struct hlist_node *node;
> + struct debug_name *element;
> +
> + element = NULL;
> + head = &module_table[hash];
> + hlist_for_each_entry_rcu(element, node, head, hlist)
> + if (!strcmp(element->name, module_name))
> + return element;
> + return NULL;
> +}
> +
Please add kernel-doc comments for the exported/public interfaces.
> +int unregister_dynamic_debug_module(char *mod_name)
> +{
> + struct debug_name *element;
> + int ret = 0;
> +
> + down(&debug_list_mutex);
> + element = find_debug_module(mod_name);
> + if (!element) {
> + ret = -EINVAL;
> + goto out;
> + }
> + hlist_del_rcu(&element->hlist);
> + hlist_del_rcu(&element->hlist2);
> + synchronize_rcu();
> + if (element->name)
> + kfree(element->name);
> + if (element->enable)
> + num_enabled--;
> + kfree(element);
> + nr_entries--;
> +out:
> + up(&debug_list_mutex);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(unregister_dynamic_debug_module);
> +
> +int register_dynamic_debug_module(char *mod_name, int type, char *share_name,
> + char *flags, int hash, int hash2)
> +{
> + struct debug_name *elem;
> + int ret = 0;
> +
> + down(&debug_list_mutex);
> + elem = find_debug_module(mod_name);
> + if (!elem) {
> + if (__add_debug_module(mod_name, hash, hash2))
> + goto out;
> + elem = find_debug_module(mod_name);
> + if (dynamic_enabled == DYNAMIC_ENABLED_ALL &&
> + !strcmp(mod_name, share_name)) {
> + elem->enable = true;
> + num_enabled++;
> + }
> + }
> + elem->type |= type;
> +out:
> + up(&debug_list_mutex);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(register_dynamic_debug_module);
> +
> diff --git a/scripts/basic/hash.c b/scripts/basic/hash.c
> new file mode 100644
> index 0000000..3299ad7
> --- /dev/null
> +++ b/scripts/basic/hash.c
> @@ -0,0 +1,64 @@
> +/*
> + * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
> + *
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#define DYNAMIC_DEBUG_HASH_BITS 6
> +
> +static const char *program;
> +
> +static void usage(void)
> +{
> + printf("Usage: %s <djb2|r5> <modname>\n", program);
> + exit(1);
> +}
> +
> +/* djb2 hashing algorithm by Dan Bernstein. From:
> + * http://www.cse.yorku.ca/~oz/hash.html
> + */
> +
> +unsigned int djb2_hash(char *str)
> +{
> + unsigned long hash = 5381;
> + int c;
> +
> + c = *str;
> + while (c) {
> + hash = ((hash << 5) + hash) + c;
> + c = *++str;
> + }
> + return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
> +}
> +
> +unsigned int r5_hash(char *str)
> +{
> + unsigned long hash = 0;
> + int c;
> +
> + c = *str;
> + while (c) {
> + hash = (hash + (c << 4) + (c >> 4)) * 11;
> + c = *++str;
> + }
> + return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + program = argv[0];
> +
> + if (argc != 3)
> + usage();
> + if (!strcmp(argv[1], "djb2"))
> + printf("%d\n", djb2_hash(argv[2]));
> + else if (!strcmp(argv[1], "r5"))
> + printf("%d\n", r5_hash(argv[2]));
> + else
> + usage();
> + exit(0);
> +}
---
~Randy
Linux Plumbers Conference, 17-19 September 2008, Portland, Oregon USA
http://linuxplumbersconf.org/
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-09 1:07 ` Greg KH
@ 2008-08-11 14:12 ` Jason Baron
2008-08-11 16:45 ` Greg KH
0 siblings, 1 reply; 29+ messages in thread
From: Jason Baron @ 2008-08-11 14:12 UTC (permalink / raw)
To: Greg KH; +Cc: linux-kernel, akpm, joe, nick, randy.dunlap
On Fri, Aug 08, 2008 at 06:07:41PM -0700, Greg KH wrote:
> > Few notes...there is still one control file: <debugfs>/dynamic_printk/modules
> > We can split this up now or later, but I kind of like being able to see all
> > the controls in one file. Also, i've used a djb2 hash function in the code,
> > which i'm not sure is under the correct license/copyright, so i just wanted
> > to point that out as well. see: scripts/basic/hash.c. If its an issue, i can
> > find another hash function.
>
> Why use that hash function? Actually, it looks like you are using 2
> different ones, right? Why?
>
The hash functions are used to map between the calling module name,
KBUILD_MODNAME, and whether or not debugging is enabled. In the 'fast' case a
bitmask is used to represent each hash bucket. One bit per bucket. Thus, if
all the modules in a bucket are disabled the bitmask is simply 0. Two
hashes are used in order to reduce the probability of collisions, used in this
way it is similar to a bloom filter. The code that implements this is:
#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ \
int ret = 0; \
if (unlikely((dynamic_printk_enabled & (1LL << DEBUG_HASH)) && \
(dynamic_printk_enabled2 & (1LL << DEBUG_HASH2)))) \
ret = __dynamic_dbg_enabled_helper(module, type, \
value, hash);\
ret; })
where DEBUG_HASH and DEBUG_HASH2 are computed at compile time. Thus, in the
'fast' case where debugging is off, we have two extra intructions, a test and
a jmp. Further, if we enable debugging for a single module, we will at most
do two 'tests' and a jump for disabled modules. If the module is enabled, we
would call through to __dynamic_dbg_enabled_helper(), which verifies whether
or not debugging is enabled for the module. I believe if we are then calling
'printk()' the cost of this function call is 'in the noise'. Thus, i've tried
to optimize the disabled case.
> > --- /dev/null
> > +++ b/include/linux/dynamic_printk.h
> > @@ -0,0 +1,94 @@
> > +#ifndef _DYNAMIC_PRINTK_H
> > +#define _DYNAMIC_PRINTK_H
> > +
> > +#ifdef __KERNEL__
>
> Shouldn't be needed.
>
ok
> > +#include <linux/string.h>
> > +#include <linux/hash.h>
> > +
> > +#define DYNAMIC_DEBUG_HASH_BITS 6
> > +#define DEBUG_HASH_TABLE_SIZE (1 << DYNAMIC_DEBUG_HASH_BITS)
> > +
> > +#define TYPE_BOOLEAN 1
>
> What's this for?
>
This is really in anticipation of more 'involved' dynamic debugging. That is,
'TYPE_BOOLEAN', just means the debugging is either off/on. The other types
are 'TYPE_FLAG', where you can control debugging for a module via a bitmask,
or 'TYPE_LEVEL', where you control the debugging for a module via a level
control like printk levels. These different types were implemented in the
orginal patchset.
> > +#define DYNAMIC_ENABLED_ALL 0
> > +#define DYNAMIC_ENABLED_NONE 1
> > +#define DYNAMIC_ENABLED_SOME 2
> > +
> > +extern int dynamic_enabled;
> > +extern long long dynamic_printk_enabled;
> > +extern long long dynamic_printk_enabled2;
>
> What's up with the "2" versions?
>
"2" here is the second bitmask as explained previously.
thanks,
-Jason
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-11 14:12 ` Jason Baron
@ 2008-08-11 16:45 ` Greg KH
0 siblings, 0 replies; 29+ messages in thread
From: Greg KH @ 2008-08-11 16:45 UTC (permalink / raw)
To: Jason Baron; +Cc: linux-kernel, akpm, joe, nick, randy.dunlap
On Mon, Aug 11, 2008 at 10:12:34AM -0400, Jason Baron wrote:
> > What's up with the "2" versions?
> >
>
> "2" here is the second bitmask as explained previously.
Great, thanks for doing this, can you put this description in the code
so it doesn't come up again? :)
thanks,
greg k-h
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-09 2:38 ` Randy Dunlap
@ 2008-08-11 17:36 ` Jason Baron
2008-08-11 22:33 ` Greg KH
0 siblings, 1 reply; 29+ messages in thread
From: Jason Baron @ 2008-08-11 17:36 UTC (permalink / raw)
To: Randy Dunlap; +Cc: Greg KH, linux-kernel, akpm, joe, nick
On Fri, Aug 08, 2008 at 07:38:51PM -0700, Randy Dunlap wrote:
> On Fri, 8 Aug 2008 17:51:53 -0400 Jason Baron wrote:
>
> > Few notes...there is still one control file: <debugfs>/dynamic_printk/modules
> > We can split this up now or later, but I kind of like being able to see all
> > the controls in one file. Also, i've used a djb2 hash function in the code,
> > which i'm not sure is under the correct license/copyright, so i just wanted
> > to point that out as well. see: scripts/basic/hash.c. If its an issue, i can
> > find another hash function.
>
> What license does it have? I don't see one.
>
hmmm...a search for djb2 finds a number of users, for example, i found this one
which is covered by GPL2, http://www.telegraphics.com.au/svn/dpa/trunk/symtab.c
is that sufficient to say its ok?
i'll clean up the additional points that you raised.
thanks,
-Jason
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-11 17:36 ` Jason Baron
@ 2008-08-11 22:33 ` Greg KH
2008-08-12 19:48 ` Jason Baron
0 siblings, 1 reply; 29+ messages in thread
From: Greg KH @ 2008-08-11 22:33 UTC (permalink / raw)
To: Jason Baron; +Cc: Randy Dunlap, linux-kernel, akpm, joe, nick
On Mon, Aug 11, 2008 at 01:36:16PM -0400, Jason Baron wrote:
> On Fri, Aug 08, 2008 at 07:38:51PM -0700, Randy Dunlap wrote:
> > On Fri, 8 Aug 2008 17:51:53 -0400 Jason Baron wrote:
> >
> > > Few notes...there is still one control file: <debugfs>/dynamic_printk/modules
> > > We can split this up now or later, but I kind of like being able to see all
> > > the controls in one file. Also, i've used a djb2 hash function in the code,
> > > which i'm not sure is under the correct license/copyright, so i just wanted
> > > to point that out as well. see: scripts/basic/hash.c. If its an issue, i can
> > > find another hash function.
> >
> > What license does it have? I don't see one.
> >
>
> hmmm...a search for djb2 finds a number of users, for example, i found this one
> which is covered by GPL2, http://www.telegraphics.com.au/svn/dpa/trunk/symtab.c
> is that sufficient to say its ok?
That's a tough call. I'd run that through the license board of your
employer if you have any questions about this, as it is your name with
their domain that is going to have the "signed-off-by:" pointing back
to.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-11 22:33 ` Greg KH
@ 2008-08-12 19:48 ` Jason Baron
2008-08-12 20:09 ` Greg KH
0 siblings, 1 reply; 29+ messages in thread
From: Jason Baron @ 2008-08-12 19:48 UTC (permalink / raw)
To: Greg KH; +Cc: Randy Dunlap, linux-kernel, akpm, joe, nick
On Mon, Aug 11, 2008 at 03:33:09PM -0700, Greg KH wrote:
> On Mon, Aug 11, 2008 at 01:36:16PM -0400, Jason Baron wrote:
> > On Fri, Aug 08, 2008 at 07:38:51PM -0700, Randy Dunlap wrote:
> > > On Fri, 8 Aug 2008 17:51:53 -0400 Jason Baron wrote:
> > >
> > > > Few notes...there is still one control file: <debugfs>/dynamic_printk/modules
> > > > We can split this up now or later, but I kind of like being able to see all
> > > > the controls in one file. Also, i've used a djb2 hash function in the code,
> > > > which i'm not sure is under the correct license/copyright, so i just wanted
> > > > to point that out as well. see: scripts/basic/hash.c. If its an issue, i can
> > > > find another hash function.
> > >
> > > What license does it have? I don't see one.
> > >
> >
> > hmmm...a search for djb2 finds a number of users, for example, i found this one
> > which is covered by GPL2, http://www.telegraphics.com.au/svn/dpa/trunk/symtab.c
> > is that sufficient to say its ok?
>
> That's a tough call. I'd run that through the license board of your
> employer if you have any questions about this, as it is your name with
> their domain that is going to have the "signed-off-by:" pointing back
> to.
>
We're ok with the patch as is...i'm including an updated version below, which
contains some documentation improvements...as you mentioned before, perhaps
you can include this patch through the driver tree. It should apply with
minimal munging, but please point me at a tree, if there are any issues.
thanks,
-Jason
Signed-off-by: Jason Baron <jbaron@redhat.com>
---
Documentation/kernel-parameters.txt | 5
include/asm-generic/vmlinux.lds.h | 10 +
include/linux/device.h | 6 -
include/linux/dynamic_printk.h | 96 ++++++++
include/linux/kernel.h | 7 +
include/linux/module.h | 4
kernel/module.c | 22 ++
lib/Kconfig.debug | 55 +++++
lib/Makefile | 2
lib/dynamic_printk.c | 413 +++++++++++++++++++++++++++++++++++
net/netfilter/nf_conntrack_pptp.c | 2
scripts/Makefile.lib | 11 +
scripts/basic/Makefile | 2
scripts/basic/hash.c | 64 +++++
14 files changed, 693 insertions(+), 6 deletions(-)
create mode 100644 include/linux/dynamic_printk.h
create mode 100644 lib/dynamic_printk.c
create mode 100644 scripts/basic/hash.c
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index bf6303e..7c60e89 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1580,6 +1580,11 @@ and is between 256 and 4096 characters. It is defined in the file
autoconfiguration.
Ranges are in pairs (memory base and size).
+ dynamic_printk
+ Enables pr_debug()/dev_dbg() calls if
+ CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled. These can also
+ be switched on/off via <debugfs>/dynamic_printk/modules
+
print-fatal-signals=
[KNL] debug: print fatal signals
print-fatal-signals=1: print segfault info to
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index f054778..00804e0 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -249,7 +249,15 @@
CPU_DISCARD(init.data) \
CPU_DISCARD(init.rodata) \
MEM_DISCARD(init.data) \
- MEM_DISCARD(init.rodata)
+ MEM_DISCARD(init.rodata) \
+ /* implement dynamic printk debug */ \
+ VMLINUX_SYMBOL(__start___verbose_strings) = .; \
+ *(__verbose_strings) \
+ VMLINUX_SYMBOL(__stop___verbose_strings) = .; \
+ . = ALIGN(8); \
+ VMLINUX_SYMBOL(__start___verbose) = .; \
+ *(__verbose) \
+ VMLINUX_SYMBOL(__stop___verbose) = .;
#define INIT_TEXT \
*(.init.text) \
diff --git a/include/linux/device.h b/include/linux/device.h
index 1a06026..fb03dbc 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -592,7 +592,11 @@ extern const char *dev_driver_string(struct device *dev);
#define dev_info(dev, format, arg...) \
dev_printk(KERN_INFO , dev , format , ## arg)
-#ifdef DEBUG
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#define dev_dbg(dev, format, ...) do { \
+ dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
+ } while (0)
+#elif defined(DEBUG)
#define dev_dbg(dev, format, arg...) \
dev_printk(KERN_DEBUG , dev , format , ## arg)
#else
diff --git a/include/linux/dynamic_printk.h b/include/linux/dynamic_printk.h
new file mode 100644
index 0000000..210bf61
--- /dev/null
+++ b/include/linux/dynamic_printk.h
@@ -0,0 +1,96 @@
+#ifndef _DYNAMIC_PRINTK_H
+#define _DYNAMIC_PRINTK_H
+
+#include <linux/string.h>
+#include <linux/hash.h>
+
+#define DYNAMIC_DEBUG_HASH_BITS 6
+#define DEBUG_HASH_TABLE_SIZE (1 << DYNAMIC_DEBUG_HASH_BITS)
+
+#define TYPE_BOOLEAN 1
+
+#define DYNAMIC_ENABLED_ALL 0
+#define DYNAMIC_ENABLED_NONE 1
+#define DYNAMIC_ENABLED_SOME 2
+
+extern int dynamic_enabled;
+
+/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
+ * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
+ * use independent hash functions, to reduce the chance of false positives.
+ */
+extern long long dynamic_printk_enabled;
+extern long long dynamic_printk_enabled2;
+
+struct mod_debug {
+ char *modname;
+ char *logical_modname;
+ char *flag_names;
+ int type;
+ int hash;
+ int hash2;
+} __attribute__((aligned(8)));
+
+int register_dynamic_debug_module(char *mod_name, int type, char *share_name,
+ char *flags, int hash, int hash2);
+
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+extern int unregister_dynamic_debug_module(char *mod_name);
+extern int __dynamic_dbg_enabled_helper(char *modname, int type,
+ int value, int hash);
+
+#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ \
+ int ret = 0; \
+ if (unlikely((dynamic_printk_enabled & (1LL << DEBUG_HASH)) && \
+ (dynamic_printk_enabled2 & (1LL << DEBUG_HASH2)))) \
+ ret = __dynamic_dbg_enabled_helper(module, type, \
+ value, hash);\
+ ret; })
+
+#define dynamic_pr_debug(fmt, ...) do { \
+ static char mod_name[] \
+ __attribute__((section("__verbose_strings"))) \
+ = KBUILD_MODNAME; \
+ static struct mod_debug descriptor \
+ __used \
+ __attribute__((section("__verbose"), aligned(8))) = \
+ { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\
+ if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \
+ 0, 0, DEBUG_HASH)) \
+ printk(KERN_DEBUG KBUILD_MODNAME ":" fmt, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#define dynamic_dev_dbg(dev, format, ...) do { \
+ static char mod_name[] \
+ __attribute__((section("__verbose_strings"))) \
+ = KBUILD_MODNAME; \
+ static struct mod_debug descriptor \
+ __used \
+ __attribute__((section("__verbose"), aligned(8))) = \
+ { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\
+ if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \
+ 0, 0, DEBUG_HASH)) \
+ dev_printk(KERN_DEBUG, dev, \
+ KBUILD_MODNAME ": " format, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#else
+
+static inline int unregister_dynamic_debug_module(const char *mod_name)
+{
+ return 0;
+}
+static inline int __dynamic_dbg_enabled_helper(char *modname, int type,
+ int value, int hash)
+{
+ return 0;
+}
+
+#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ 0; })
+#define dynamic_pr_debug(fmt, ...) do { } while (0)
+#define dynamic_dev_dbg(dev, format, ...) do { } while (0)
+#endif
+
+#endif
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index cd6d02c..25d09b8 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -14,6 +14,7 @@
#include <linux/compiler.h>
#include <linux/bitops.h>
#include <linux/log2.h>
+#include <linux/dynamic_printk.h>
#include <asm/byteorder.h>
#include <asm/bug.h>
@@ -288,8 +289,12 @@ extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
#define pr_info(fmt, arg...) \
printk(KERN_INFO fmt, ##arg)
-#ifdef DEBUG
/* If you are writing a driver, please use dev_dbg instead */
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#define pr_debug(fmt, ...) do { \
+ dynamic_pr_debug(fmt, ##__VA_ARGS__); \
+ } while (0)
+#elif defined(DEBUG)
#define pr_debug(fmt, arg...) \
printk(KERN_DEBUG fmt, ##arg)
#else
diff --git a/include/linux/module.h b/include/linux/module.h
index 819c4e8..74a2e32 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -359,6 +359,10 @@ struct module
struct marker *markers;
unsigned int num_markers;
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ struct mod_debug *start_verbose;
+ unsigned int num_verbose;
+#endif
};
#ifndef MODULE_ARCH_INIT
#define MODULE_ARCH_INIT {}
diff --git a/kernel/module.c b/kernel/module.c
index 8d6cccc..ad7a105 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -744,6 +744,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
}
/* Store the name of the last unloaded module for diagnostic purposes */
strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
+ unregister_dynamic_debug_module(mod->name);
free_module(mod);
out:
@@ -1717,6 +1718,9 @@ static struct module *load_module(void __user *umod,
unsigned int unusedgplcrcindex;
unsigned int markersindex;
unsigned int markersstringsindex;
+ unsigned int verboseindex;
+ struct mod_debug *iter;
+ unsigned long value;
struct module *mod;
long err = 0;
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1993,6 +1997,7 @@ static struct module *load_module(void __user *umod,
markersindex = find_sec(hdr, sechdrs, secstrings, "__markers");
markersstringsindex = find_sec(hdr, sechdrs, secstrings,
"__markers_strings");
+ verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose");
/* Now do relocations. */
for (i = 1; i < hdr->e_shnum; i++) {
@@ -2020,6 +2025,11 @@ static struct module *load_module(void __user *umod,
mod->num_markers =
sechdrs[markersindex].sh_size / sizeof(*mod->markers);
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ mod->start_verbose = (void *)sechdrs[verboseindex].sh_addr;
+ mod->num_verbose = sechdrs[verboseindex].sh_size /
+ sizeof(*mod->start_verbose);
+#endif
/* Find duplicate symbols */
err = verify_export_symbols(mod);
@@ -2043,6 +2053,18 @@ static struct module *load_module(void __user *umod,
marker_update_probe_range(mod->markers,
mod->markers + mod->num_markers);
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ for (value = (unsigned long)mod->start_verbose;
+ value < (unsigned long)mod->start_verbose +
+ (unsigned long)(mod->num_verbose * sizeof(struct mod_debug));
+ value += sizeof(struct mod_debug)) {
+ iter = (struct mod_debug *)value;
+ register_dynamic_debug_module(iter->modname,
+ iter->type,
+ iter->logical_modname,
+ iter->flag_names, iter->hash, iter->hash2);
+ }
+#endif
err = module_finalize(hdr, sechdrs, mod);
if (err < 0)
goto cleanup;
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 623ef24..01b2a23 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -632,6 +632,61 @@ config FIREWIRE_OHCI_REMOTE_DMA
If unsure, say N.
+config DYNAMIC_PRINTK_DEBUG
+ bool "Enable dynamic printk() call support"
+ default n
+ depends on PRINTK
+ select PRINTK_DEBUG
+ help
+
+ Compiles debug level messages into the kernel, which would not
+ otherwise be available at runtime. These messages can then be
+ enabled/disabled on a per module basis. This mechanism implicitly
+ enables all pr_debug() and dev_dbg() calls. The impact of this
+ compile option is a larger kernel text size of about 2%.
+
+ Usage:
+
+ Dynamic debugging is controlled by the debugfs file,
+ dynamic_printk/modules. This file contains a list of the modules that
+ can be enabled. The format of the file is the module name, followed
+ by a set of flags that can be enabled. The first flag is always the
+ 'enabled' flag. For example:
+
+ <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
+
+ From a live system:
+
+ snd_hda_intel enabled=0
+ fixup enabled=0
+ 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.
+
source "samples/Kconfig"
source "lib/Kconfig.kgdb"
diff --git a/lib/Makefile b/lib/Makefile
index bf8000f..78ab656 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -70,6 +70,8 @@ lib-$(CONFIG_GENERIC_BUG) += bug.o
obj-$(CONFIG_HAVE_LMB) += lmb.o
+obj-$(CONFIG_DYNAMIC_PRINTK_DEBUG) += dynamic_printk.o
+
hostprogs-y := gen_crc32table
clean-files := crc32table.h
diff --git a/lib/dynamic_printk.c b/lib/dynamic_printk.c
new file mode 100644
index 0000000..ea679ec
--- /dev/null
+++ b/lib/dynamic_printk.c
@@ -0,0 +1,413 @@
+/*
+ * lib/dynamic_printk.c
+ *
+ * make pr_debug()/dev_dbg() calls runtime configurable based upon their
+ * their source module.
+ *
+ * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+
+extern struct mod_debug __start___verbose[];
+extern struct mod_debug __stop___verbose[];
+
+struct debug_name {
+ struct hlist_node hlist;
+ struct hlist_node hlist2;
+ int hash1;
+ int hash2;
+ char *name;
+ int enable;
+ int type;
+};
+
+static int nr_entries;
+static int num_enabled;
+int dynamic_enabled = DYNAMIC_ENABLED_NONE;
+static struct hlist_head module_table[DEBUG_HASH_TABLE_SIZE] =
+ { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
+static struct hlist_head module_table2[DEBUG_HASH_TABLE_SIZE] =
+ { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
+static DECLARE_MUTEX(debug_list_mutex);
+
+/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
+ * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
+ * use independent hash functions, to reduce the chance of false positives.
+ */
+long long dynamic_printk_enabled;
+EXPORT_SYMBOL_GPL(dynamic_printk_enabled);
+long long dynamic_printk_enabled2;
+EXPORT_SYMBOL_GPL(dynamic_printk_enabled2);
+
+/* returns the debug module pointer. */
+static struct debug_name *find_debug_module(char *module_name)
+{
+ int i;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *element;
+
+ element = NULL;
+ for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
+ head = &module_table[i];
+ hlist_for_each_entry_rcu(element, node, head, hlist)
+ if (!strcmp(element->name, module_name))
+ return element;
+ }
+ return NULL;
+}
+
+/* returns the debug module pointer. */
+static struct debug_name *find_debug_module_hash(char *module_name, int hash)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *element;
+
+ element = NULL;
+ head = &module_table[hash];
+ hlist_for_each_entry_rcu(element, node, head, hlist)
+ if (!strcmp(element->name, module_name))
+ return element;
+ return NULL;
+}
+
+/* caller must hold mutex*/
+static int __add_debug_module(char *mod_name, int hash, int hash2)
+{
+ struct debug_name *new;
+ char *module_name;
+ int ret = 0;
+
+ if (find_debug_module(mod_name)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ module_name = kmalloc(strlen(mod_name) + 1, GFP_KERNEL);
+ if (!module_name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ module_name = strcpy(module_name, mod_name);
+ module_name[strlen(mod_name)] = '\0';
+ new = kzalloc(sizeof(struct debug_name), GFP_KERNEL);
+ if (!new) {
+ kfree(module_name);
+ ret = -ENOMEM;
+ goto out;
+ }
+ INIT_HLIST_NODE(&new->hlist);
+ INIT_HLIST_NODE(&new->hlist2);
+ new->name = module_name;
+ new->hash1 = hash;
+ new->hash2 = hash2;
+ hlist_add_head_rcu(&new->hlist, &module_table[hash]);
+ hlist_add_head_rcu(&new->hlist2, &module_table2[hash2]);
+ nr_entries++;
+out:
+ return ret;
+}
+
+int unregister_dynamic_debug_module(char *mod_name)
+{
+ struct debug_name *element;
+ int ret = 0;
+
+ down(&debug_list_mutex);
+ element = find_debug_module(mod_name);
+ if (!element) {
+ ret = -EINVAL;
+ goto out;
+ }
+ hlist_del_rcu(&element->hlist);
+ hlist_del_rcu(&element->hlist2);
+ synchronize_rcu();
+ if (element->name)
+ kfree(element->name);
+ if (element->enable)
+ num_enabled--;
+ kfree(element);
+ nr_entries--;
+out:
+ up(&debug_list_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(unregister_dynamic_debug_module);
+
+int register_dynamic_debug_module(char *mod_name, int type, char *share_name,
+ char *flags, int hash, int hash2)
+{
+ struct debug_name *elem;
+ int ret = 0;
+
+ down(&debug_list_mutex);
+ elem = find_debug_module(mod_name);
+ if (!elem) {
+ if (__add_debug_module(mod_name, hash, hash2))
+ goto out;
+ elem = find_debug_module(mod_name);
+ if (dynamic_enabled == DYNAMIC_ENABLED_ALL &&
+ !strcmp(mod_name, share_name)) {
+ elem->enable = true;
+ num_enabled++;
+ }
+ }
+ elem->type |= type;
+out:
+ up(&debug_list_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_dynamic_debug_module);
+
+int __dynamic_dbg_enabled_helper(char *mod_name, int type, int value, int hash)
+{
+ struct debug_name *elem;
+ int ret = 0;
+
+ if (dynamic_enabled == DYNAMIC_ENABLED_ALL)
+ return 1;
+ rcu_read_lock();
+ elem = find_debug_module_hash(mod_name, hash);
+ if (elem && elem->enable)
+ ret = 1;
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__dynamic_dbg_enabled_helper);
+
+static void set_all(bool enable)
+{
+ struct debug_name *e;
+ struct hlist_node *node;
+ int i;
+ long long enable_mask;
+
+ for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
+ if (module_table[i].first != NULL) {
+ hlist_for_each_entry(e, node, &module_table[i], hlist) {
+ e->enable = enable;
+ }
+ }
+ }
+ if (enable)
+ enable_mask = ULLONG_MAX;
+ else
+ enable_mask = 0;
+ dynamic_printk_enabled = enable_mask;
+ dynamic_printk_enabled2 = enable_mask;
+}
+
+static int disabled_hash(int i, bool first_table)
+{
+ struct debug_name *e;
+ struct hlist_node *node;
+
+ if (first_table) {
+ hlist_for_each_entry(e, node, &module_table[i], hlist) {
+ if (e->enable)
+ return 0;
+ }
+ } else {
+ hlist_for_each_entry(e, node, &module_table2[i], hlist2) {
+ if (e->enable)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static ssize_t pr_debug_write(struct file *file, const char __user *buf,
+ size_t length, loff_t *ppos)
+{
+ char *buffer, *s, *value_str, *setting_str;
+ int err, value;
+ struct debug_name *elem = NULL;
+ int all = 0;
+
+ if (length > PAGE_SIZE || length < 0)
+ return -EINVAL;
+
+ buffer = (char *)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ err = -EFAULT;
+ if (copy_from_user(buffer, buf, length))
+ goto out;
+
+ err = -EINVAL;
+ if (length < PAGE_SIZE)
+ buffer[length] = '\0';
+ else if (buffer[PAGE_SIZE-1])
+ goto out;
+
+ err = -EINVAL;
+ down(&debug_list_mutex);
+
+ if (strncmp("set", buffer, 3))
+ goto out_up;
+ s = buffer + 3;
+ setting_str = strsep(&s, "=");
+ if (s == NULL)
+ goto out_up;
+ setting_str = strstrip(setting_str);
+ value_str = strsep(&s, " ");
+ if (s == NULL)
+ goto out_up;
+ s = strstrip(s);
+ if (!strncmp(s, "all", 3))
+ all = 1;
+ else
+ elem = find_debug_module(s);
+ if (!strncmp(setting_str, "enable", 6)) {
+ value = !!simple_strtol(value_str, NULL, 10);
+ if (all) {
+ if (value) {
+ set_all(true);
+ num_enabled = nr_entries;
+ dynamic_enabled = DYNAMIC_ENABLED_ALL;
+ } else {
+ set_all(false);
+ num_enabled = 0;
+ dynamic_enabled = DYNAMIC_ENABLED_NONE;
+ }
+ err = 0;
+ } else {
+ if (elem) {
+ if (value && (elem->enable == 0)) {
+ dynamic_printk_enabled |=
+ (1LL << elem->hash1);
+ dynamic_printk_enabled2 |=
+ (1LL << elem->hash2);
+ elem->enable = 1;
+ num_enabled++;
+ dynamic_enabled = DYNAMIC_ENABLED_SOME;
+ err = 0;
+ } else if (!value && (elem->enable == 1)) {
+ elem->enable = 0;
+ num_enabled--;
+ if (disabled_hash(elem->hash1, true))
+ dynamic_printk_enabled &=
+ ~(1LL << elem->hash1);
+ if (disabled_hash(elem->hash2, false))
+ dynamic_printk_enabled2 &=
+ ~(1LL << elem->hash2);
+ if (num_enabled)
+ dynamic_enabled =
+ DYNAMIC_ENABLED_SOME;
+ else
+ dynamic_enabled =
+ DYNAMIC_ENABLED_NONE;
+ err = 0;
+ }
+ }
+ }
+ }
+ if (!err)
+ err = length;
+out_up:
+ up(&debug_list_mutex);
+out:
+ free_page((unsigned long)buffer);
+ return err;
+}
+
+static void *pr_debug_seq_start(struct seq_file *f, loff_t *pos)
+{
+ return (*pos < DEBUG_HASH_TABLE_SIZE) ? pos : NULL;
+}
+
+static void *pr_debug_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ (*pos)++;
+ if (*pos >= DEBUG_HASH_TABLE_SIZE)
+ return NULL;
+ return pos;
+}
+
+static void pr_debug_seq_stop(struct seq_file *s, void *v)
+{
+ /* Nothing to do */
+}
+
+static int pr_debug_seq_show(struct seq_file *s, void *v)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *elem;
+ unsigned int i = *(loff_t *) v;
+
+ rcu_read_lock();
+ head = &module_table[i];
+ hlist_for_each_entry_rcu(elem, node, head, hlist) {
+ seq_printf(s, "%s enabled=%d", elem->name, elem->enable);
+ seq_printf(s, "\n");
+ }
+ rcu_read_unlock();
+ return 0;
+}
+
+static struct seq_operations pr_debug_seq_ops = {
+ .start = pr_debug_seq_start,
+ .next = pr_debug_seq_next,
+ .stop = pr_debug_seq_stop,
+ .show = pr_debug_seq_show
+};
+
+static int pr_debug_open(struct inode *inode, struct file *filp)
+{
+ return seq_open(filp, &pr_debug_seq_ops);
+}
+
+static const struct file_operations pr_debug_operations = {
+ .open = pr_debug_open,
+ .read = seq_read,
+ .write = pr_debug_write,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+int __init dynamic_printk_init(void)
+{
+ struct dentry *dir, *file;
+ struct mod_debug *iter;
+ unsigned long value;
+
+ dir = debugfs_create_dir("dynamic_printk", NULL);
+ if (!dir)
+ return -ENOMEM;
+ file = debugfs_create_file("modules", 0644, dir, NULL,
+ &pr_debug_operations);
+ if (!file) {
+ debugfs_remove(dir);
+ return -ENOMEM;
+ }
+ for (value = (unsigned long)__start___verbose;
+ value < (unsigned long)__stop___verbose;
+ value += sizeof(struct mod_debug)) {
+ iter = (struct mod_debug *)value;
+ register_dynamic_debug_module(iter->modname,
+ iter->type,
+ iter->logical_modname,
+ iter->flag_names, iter->hash, iter->hash2);
+ }
+ return 0;
+}
+module_init(dynamic_printk_init);
+/* may want to move this earlier so we can get traces as early as possible */
+
+static int __init dynamic_printk_setup(char *str)
+{
+ if (str)
+ return -ENOENT;
+ set_all(true);
+ return 0;
+}
+/* Use early_param(), so we can get debug output as early as possible */
+early_param("dynamic_printk", dynamic_printk_setup);
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index 97e54b0..7fea304 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -65,7 +65,7 @@ void
struct nf_conntrack_expect *exp) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn);
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
/* PptpControlMessageType names */
const char *const pptp_msg_name[] = {
"UNKNOWN_MESSAGE",
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 8e44023..1e393cf 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -96,6 +96,14 @@ basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
modname_flags = $(if $(filter 1,$(words $(modname))),\
-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+#hash values
+ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\
+ -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))"
+else
+debug_flags =
+endif
+
_c_flags = $(KBUILD_CFLAGS) $(ccflags-y) $(CFLAGS_$(basetarget).o)
_a_flags = $(KBUILD_AFLAGS) $(asflags-y) $(AFLAGS_$(basetarget).o)
_cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F))
@@ -120,7 +128,8 @@ endif
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
$(__c_flags) $(modkern_cflags) \
- -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+ -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \
+ $(debug_flags)
a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
$(__a_flags) $(modkern_aflags)
diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile
index 4c324a1..0955995 100644
--- a/scripts/basic/Makefile
+++ b/scripts/basic/Makefile
@@ -9,7 +9,7 @@
# fixdep: Used to generate dependency information during build process
# docproc: Used in Documentation/DocBook
-hostprogs-y := fixdep docproc
+hostprogs-y := fixdep docproc hash
always := $(hostprogs-y)
# fixdep is needed to compile other host programs
diff --git a/scripts/basic/hash.c b/scripts/basic/hash.c
new file mode 100644
index 0000000..3299ad7
--- /dev/null
+++ b/scripts/basic/hash.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define DYNAMIC_DEBUG_HASH_BITS 6
+
+static const char *program;
+
+static void usage(void)
+{
+ printf("Usage: %s <djb2|r5> <modname>\n", program);
+ exit(1);
+}
+
+/* djb2 hashing algorithm by Dan Bernstein. From:
+ * http://www.cse.yorku.ca/~oz/hash.html
+ */
+
+unsigned int djb2_hash(char *str)
+{
+ unsigned long hash = 5381;
+ int c;
+
+ c = *str;
+ while (c) {
+ hash = ((hash << 5) + hash) + c;
+ c = *++str;
+ }
+ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
+}
+
+unsigned int r5_hash(char *str)
+{
+ unsigned long hash = 0;
+ int c;
+
+ c = *str;
+ while (c) {
+ hash = (hash + (c << 4) + (c >> 4)) * 11;
+ c = *++str;
+ }
+ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
+}
+
+int main(int argc, char *argv[])
+{
+ program = argv[0];
+
+ if (argc != 3)
+ usage();
+ if (!strcmp(argv[1], "djb2"))
+ printf("%d\n", djb2_hash(argv[2]));
+ else if (!strcmp(argv[1], "r5"))
+ printf("%d\n", r5_hash(argv[2]));
+ else
+ usage();
+ exit(0);
+}
+
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-12 19:48 ` Jason Baron
@ 2008-08-12 20:09 ` Greg KH
2008-08-12 20:46 ` Jason Baron
0 siblings, 1 reply; 29+ messages in thread
From: Greg KH @ 2008-08-12 20:09 UTC (permalink / raw)
To: Jason Baron; +Cc: Randy Dunlap, linux-kernel, akpm, joe, nick
On Tue, Aug 12, 2008 at 03:48:17PM -0400, Jason Baron wrote:
> On Mon, Aug 11, 2008 at 03:33:09PM -0700, Greg KH wrote:
> > On Mon, Aug 11, 2008 at 01:36:16PM -0400, Jason Baron wrote:
> > > On Fri, Aug 08, 2008 at 07:38:51PM -0700, Randy Dunlap wrote:
> > > > On Fri, 8 Aug 2008 17:51:53 -0400 Jason Baron wrote:
> > > >
> > > > > Few notes...there is still one control file: <debugfs>/dynamic_printk/modules
> > > > > We can split this up now or later, but I kind of like being able to see all
> > > > > the controls in one file. Also, i've used a djb2 hash function in the code,
> > > > > which i'm not sure is under the correct license/copyright, so i just wanted
> > > > > to point that out as well. see: scripts/basic/hash.c. If its an issue, i can
> > > > > find another hash function.
> > > >
> > > > What license does it have? I don't see one.
> > > >
> > >
> > > hmmm...a search for djb2 finds a number of users, for example, i found this one
> > > which is covered by GPL2, http://www.telegraphics.com.au/svn/dpa/trunk/symtab.c
> > > is that sufficient to say its ok?
> >
> > That's a tough call. I'd run that through the license board of your
> > employer if you have any questions about this, as it is your name with
> > their domain that is going to have the "signed-off-by:" pointing back
> > to.
> >
>
> We're ok with the patch as is...i'm including an updated version below, which
> contains some documentation improvements...as you mentioned before, perhaps
> you can include this patch through the driver tree. It should apply with
> minimal munging, but please point me at a tree, if there are any issues.
>
> thanks,
>
> -Jason
>
>
> Signed-off-by: Jason Baron <jbaron@redhat.com>
So close, can I have a good changelog comment with the patch so people
know what it is when they look in the logs?
Care to resend it with that?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-12 20:09 ` Greg KH
@ 2008-08-12 20:46 ` Jason Baron
2008-08-13 1:08 ` Greg KH
2008-08-14 14:53 ` Greg KH
0 siblings, 2 replies; 29+ messages in thread
From: Jason Baron @ 2008-08-12 20:46 UTC (permalink / raw)
To: Greg KH; +Cc: Randy Dunlap, linux-kernel, akpm, joe, nick
On Tue, Aug 12, 2008 at 01:09:08PM -0700, Greg KH wrote:
> So close, can I have a good changelog comment with the patch so people
> know what it is when they look in the logs?
>
> Care to resend it with that?
>
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.
Signed-off-by: Jason Baron <jbaron@redhat.com>
---
Documentation/kernel-parameters.txt | 5
include/asm-generic/vmlinux.lds.h | 10 +
include/linux/device.h | 6 -
include/linux/dynamic_printk.h | 96 ++++++++
include/linux/kernel.h | 7 +
include/linux/module.h | 4
kernel/module.c | 22 ++
lib/Kconfig.debug | 55 +++++
lib/Makefile | 2
lib/dynamic_printk.c | 413 +++++++++++++++++++++++++++++++++++
net/netfilter/nf_conntrack_pptp.c | 2
scripts/Makefile.lib | 11 +
scripts/basic/Makefile | 2
scripts/basic/hash.c | 64 +++++
14 files changed, 693 insertions(+), 6 deletions(-)
create mode 100644 include/linux/dynamic_printk.h
create mode 100644 lib/dynamic_printk.c
create mode 100644 scripts/basic/hash.c
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index bf6303e..7c60e89 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1580,6 +1580,11 @@ and is between 256 and 4096 characters. It is defined in the file
autoconfiguration.
Ranges are in pairs (memory base and size).
+ dynamic_printk
+ Enables pr_debug()/dev_dbg() calls if
+ CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled. These can also
+ be switched on/off via <debugfs>/dynamic_printk/modules
+
print-fatal-signals=
[KNL] debug: print fatal signals
print-fatal-signals=1: print segfault info to
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index f054778..00804e0 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -249,7 +249,15 @@
CPU_DISCARD(init.data) \
CPU_DISCARD(init.rodata) \
MEM_DISCARD(init.data) \
- MEM_DISCARD(init.rodata)
+ MEM_DISCARD(init.rodata) \
+ /* implement dynamic printk debug */ \
+ VMLINUX_SYMBOL(__start___verbose_strings) = .; \
+ *(__verbose_strings) \
+ VMLINUX_SYMBOL(__stop___verbose_strings) = .; \
+ . = ALIGN(8); \
+ VMLINUX_SYMBOL(__start___verbose) = .; \
+ *(__verbose) \
+ VMLINUX_SYMBOL(__stop___verbose) = .;
#define INIT_TEXT \
*(.init.text) \
diff --git a/include/linux/device.h b/include/linux/device.h
index 1a06026..fb03dbc 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -592,7 +592,11 @@ extern const char *dev_driver_string(struct device *dev);
#define dev_info(dev, format, arg...) \
dev_printk(KERN_INFO , dev , format , ## arg)
-#ifdef DEBUG
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#define dev_dbg(dev, format, ...) do { \
+ dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
+ } while (0)
+#elif defined(DEBUG)
#define dev_dbg(dev, format, arg...) \
dev_printk(KERN_DEBUG , dev , format , ## arg)
#else
diff --git a/include/linux/dynamic_printk.h b/include/linux/dynamic_printk.h
new file mode 100644
index 0000000..210bf61
--- /dev/null
+++ b/include/linux/dynamic_printk.h
@@ -0,0 +1,96 @@
+#ifndef _DYNAMIC_PRINTK_H
+#define _DYNAMIC_PRINTK_H
+
+#include <linux/string.h>
+#include <linux/hash.h>
+
+#define DYNAMIC_DEBUG_HASH_BITS 6
+#define DEBUG_HASH_TABLE_SIZE (1 << DYNAMIC_DEBUG_HASH_BITS)
+
+#define TYPE_BOOLEAN 1
+
+#define DYNAMIC_ENABLED_ALL 0
+#define DYNAMIC_ENABLED_NONE 1
+#define DYNAMIC_ENABLED_SOME 2
+
+extern int dynamic_enabled;
+
+/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
+ * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
+ * use independent hash functions, to reduce the chance of false positives.
+ */
+extern long long dynamic_printk_enabled;
+extern long long dynamic_printk_enabled2;
+
+struct mod_debug {
+ char *modname;
+ char *logical_modname;
+ char *flag_names;
+ int type;
+ int hash;
+ int hash2;
+} __attribute__((aligned(8)));
+
+int register_dynamic_debug_module(char *mod_name, int type, char *share_name,
+ char *flags, int hash, int hash2);
+
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+extern int unregister_dynamic_debug_module(char *mod_name);
+extern int __dynamic_dbg_enabled_helper(char *modname, int type,
+ int value, int hash);
+
+#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ \
+ int ret = 0; \
+ if (unlikely((dynamic_printk_enabled & (1LL << DEBUG_HASH)) && \
+ (dynamic_printk_enabled2 & (1LL << DEBUG_HASH2)))) \
+ ret = __dynamic_dbg_enabled_helper(module, type, \
+ value, hash);\
+ ret; })
+
+#define dynamic_pr_debug(fmt, ...) do { \
+ static char mod_name[] \
+ __attribute__((section("__verbose_strings"))) \
+ = KBUILD_MODNAME; \
+ static struct mod_debug descriptor \
+ __used \
+ __attribute__((section("__verbose"), aligned(8))) = \
+ { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\
+ if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \
+ 0, 0, DEBUG_HASH)) \
+ printk(KERN_DEBUG KBUILD_MODNAME ":" fmt, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#define dynamic_dev_dbg(dev, format, ...) do { \
+ static char mod_name[] \
+ __attribute__((section("__verbose_strings"))) \
+ = KBUILD_MODNAME; \
+ static struct mod_debug descriptor \
+ __used \
+ __attribute__((section("__verbose"), aligned(8))) = \
+ { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\
+ if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \
+ 0, 0, DEBUG_HASH)) \
+ dev_printk(KERN_DEBUG, dev, \
+ KBUILD_MODNAME ": " format, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#else
+
+static inline int unregister_dynamic_debug_module(const char *mod_name)
+{
+ return 0;
+}
+static inline int __dynamic_dbg_enabled_helper(char *modname, int type,
+ int value, int hash)
+{
+ return 0;
+}
+
+#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ 0; })
+#define dynamic_pr_debug(fmt, ...) do { } while (0)
+#define dynamic_dev_dbg(dev, format, ...) do { } while (0)
+#endif
+
+#endif
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index cd6d02c..25d09b8 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -14,6 +14,7 @@
#include <linux/compiler.h>
#include <linux/bitops.h>
#include <linux/log2.h>
+#include <linux/dynamic_printk.h>
#include <asm/byteorder.h>
#include <asm/bug.h>
@@ -288,8 +289,12 @@ extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
#define pr_info(fmt, arg...) \
printk(KERN_INFO fmt, ##arg)
-#ifdef DEBUG
/* If you are writing a driver, please use dev_dbg instead */
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#define pr_debug(fmt, ...) do { \
+ dynamic_pr_debug(fmt, ##__VA_ARGS__); \
+ } while (0)
+#elif defined(DEBUG)
#define pr_debug(fmt, arg...) \
printk(KERN_DEBUG fmt, ##arg)
#else
diff --git a/include/linux/module.h b/include/linux/module.h
index 819c4e8..74a2e32 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -359,6 +359,10 @@ struct module
struct marker *markers;
unsigned int num_markers;
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ struct mod_debug *start_verbose;
+ unsigned int num_verbose;
+#endif
};
#ifndef MODULE_ARCH_INIT
#define MODULE_ARCH_INIT {}
diff --git a/kernel/module.c b/kernel/module.c
index 8d6cccc..ad7a105 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -744,6 +744,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
}
/* Store the name of the last unloaded module for diagnostic purposes */
strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
+ unregister_dynamic_debug_module(mod->name);
free_module(mod);
out:
@@ -1717,6 +1718,9 @@ static struct module *load_module(void __user *umod,
unsigned int unusedgplcrcindex;
unsigned int markersindex;
unsigned int markersstringsindex;
+ unsigned int verboseindex;
+ struct mod_debug *iter;
+ unsigned long value;
struct module *mod;
long err = 0;
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1993,6 +1997,7 @@ static struct module *load_module(void __user *umod,
markersindex = find_sec(hdr, sechdrs, secstrings, "__markers");
markersstringsindex = find_sec(hdr, sechdrs, secstrings,
"__markers_strings");
+ verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose");
/* Now do relocations. */
for (i = 1; i < hdr->e_shnum; i++) {
@@ -2020,6 +2025,11 @@ static struct module *load_module(void __user *umod,
mod->num_markers =
sechdrs[markersindex].sh_size / sizeof(*mod->markers);
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ mod->start_verbose = (void *)sechdrs[verboseindex].sh_addr;
+ mod->num_verbose = sechdrs[verboseindex].sh_size /
+ sizeof(*mod->start_verbose);
+#endif
/* Find duplicate symbols */
err = verify_export_symbols(mod);
@@ -2043,6 +2053,18 @@ static struct module *load_module(void __user *umod,
marker_update_probe_range(mod->markers,
mod->markers + mod->num_markers);
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ for (value = (unsigned long)mod->start_verbose;
+ value < (unsigned long)mod->start_verbose +
+ (unsigned long)(mod->num_verbose * sizeof(struct mod_debug));
+ value += sizeof(struct mod_debug)) {
+ iter = (struct mod_debug *)value;
+ register_dynamic_debug_module(iter->modname,
+ iter->type,
+ iter->logical_modname,
+ iter->flag_names, iter->hash, iter->hash2);
+ }
+#endif
err = module_finalize(hdr, sechdrs, mod);
if (err < 0)
goto cleanup;
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 623ef24..01b2a23 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -632,6 +632,61 @@ config FIREWIRE_OHCI_REMOTE_DMA
If unsure, say N.
+config DYNAMIC_PRINTK_DEBUG
+ bool "Enable dynamic printk() call support"
+ default n
+ depends on PRINTK
+ select PRINTK_DEBUG
+ help
+
+ Compiles debug level messages into the kernel, which would not
+ otherwise be available at runtime. These messages can then be
+ enabled/disabled on a per module basis. This mechanism implicitly
+ enables all pr_debug() and dev_dbg() calls. The impact of this
+ compile option is a larger kernel text size of about 2%.
+
+ Usage:
+
+ Dynamic debugging is controlled by the debugfs file,
+ dynamic_printk/modules. This file contains a list of the modules that
+ can be enabled. The format of the file is the module name, followed
+ by a set of flags that can be enabled. The first flag is always the
+ 'enabled' flag. For example:
+
+ <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
+
+ From a live system:
+
+ snd_hda_intel enabled=0
+ fixup enabled=0
+ 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.
+
source "samples/Kconfig"
source "lib/Kconfig.kgdb"
diff --git a/lib/Makefile b/lib/Makefile
index bf8000f..78ab656 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -70,6 +70,8 @@ lib-$(CONFIG_GENERIC_BUG) += bug.o
obj-$(CONFIG_HAVE_LMB) += lmb.o
+obj-$(CONFIG_DYNAMIC_PRINTK_DEBUG) += dynamic_printk.o
+
hostprogs-y := gen_crc32table
clean-files := crc32table.h
diff --git a/lib/dynamic_printk.c b/lib/dynamic_printk.c
new file mode 100644
index 0000000..ea679ec
--- /dev/null
+++ b/lib/dynamic_printk.c
@@ -0,0 +1,413 @@
+/*
+ * lib/dynamic_printk.c
+ *
+ * make pr_debug()/dev_dbg() calls runtime configurable based upon their
+ * their source module.
+ *
+ * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+
+extern struct mod_debug __start___verbose[];
+extern struct mod_debug __stop___verbose[];
+
+struct debug_name {
+ struct hlist_node hlist;
+ struct hlist_node hlist2;
+ int hash1;
+ int hash2;
+ char *name;
+ int enable;
+ int type;
+};
+
+static int nr_entries;
+static int num_enabled;
+int dynamic_enabled = DYNAMIC_ENABLED_NONE;
+static struct hlist_head module_table[DEBUG_HASH_TABLE_SIZE] =
+ { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
+static struct hlist_head module_table2[DEBUG_HASH_TABLE_SIZE] =
+ { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
+static DECLARE_MUTEX(debug_list_mutex);
+
+/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
+ * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
+ * use independent hash functions, to reduce the chance of false positives.
+ */
+long long dynamic_printk_enabled;
+EXPORT_SYMBOL_GPL(dynamic_printk_enabled);
+long long dynamic_printk_enabled2;
+EXPORT_SYMBOL_GPL(dynamic_printk_enabled2);
+
+/* returns the debug module pointer. */
+static struct debug_name *find_debug_module(char *module_name)
+{
+ int i;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *element;
+
+ element = NULL;
+ for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
+ head = &module_table[i];
+ hlist_for_each_entry_rcu(element, node, head, hlist)
+ if (!strcmp(element->name, module_name))
+ return element;
+ }
+ return NULL;
+}
+
+/* returns the debug module pointer. */
+static struct debug_name *find_debug_module_hash(char *module_name, int hash)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *element;
+
+ element = NULL;
+ head = &module_table[hash];
+ hlist_for_each_entry_rcu(element, node, head, hlist)
+ if (!strcmp(element->name, module_name))
+ return element;
+ return NULL;
+}
+
+/* caller must hold mutex*/
+static int __add_debug_module(char *mod_name, int hash, int hash2)
+{
+ struct debug_name *new;
+ char *module_name;
+ int ret = 0;
+
+ if (find_debug_module(mod_name)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ module_name = kmalloc(strlen(mod_name) + 1, GFP_KERNEL);
+ if (!module_name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ module_name = strcpy(module_name, mod_name);
+ module_name[strlen(mod_name)] = '\0';
+ new = kzalloc(sizeof(struct debug_name), GFP_KERNEL);
+ if (!new) {
+ kfree(module_name);
+ ret = -ENOMEM;
+ goto out;
+ }
+ INIT_HLIST_NODE(&new->hlist);
+ INIT_HLIST_NODE(&new->hlist2);
+ new->name = module_name;
+ new->hash1 = hash;
+ new->hash2 = hash2;
+ hlist_add_head_rcu(&new->hlist, &module_table[hash]);
+ hlist_add_head_rcu(&new->hlist2, &module_table2[hash2]);
+ nr_entries++;
+out:
+ return ret;
+}
+
+int unregister_dynamic_debug_module(char *mod_name)
+{
+ struct debug_name *element;
+ int ret = 0;
+
+ down(&debug_list_mutex);
+ element = find_debug_module(mod_name);
+ if (!element) {
+ ret = -EINVAL;
+ goto out;
+ }
+ hlist_del_rcu(&element->hlist);
+ hlist_del_rcu(&element->hlist2);
+ synchronize_rcu();
+ if (element->name)
+ kfree(element->name);
+ if (element->enable)
+ num_enabled--;
+ kfree(element);
+ nr_entries--;
+out:
+ up(&debug_list_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(unregister_dynamic_debug_module);
+
+int register_dynamic_debug_module(char *mod_name, int type, char *share_name,
+ char *flags, int hash, int hash2)
+{
+ struct debug_name *elem;
+ int ret = 0;
+
+ down(&debug_list_mutex);
+ elem = find_debug_module(mod_name);
+ if (!elem) {
+ if (__add_debug_module(mod_name, hash, hash2))
+ goto out;
+ elem = find_debug_module(mod_name);
+ if (dynamic_enabled == DYNAMIC_ENABLED_ALL &&
+ !strcmp(mod_name, share_name)) {
+ elem->enable = true;
+ num_enabled++;
+ }
+ }
+ elem->type |= type;
+out:
+ up(&debug_list_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_dynamic_debug_module);
+
+int __dynamic_dbg_enabled_helper(char *mod_name, int type, int value, int hash)
+{
+ struct debug_name *elem;
+ int ret = 0;
+
+ if (dynamic_enabled == DYNAMIC_ENABLED_ALL)
+ return 1;
+ rcu_read_lock();
+ elem = find_debug_module_hash(mod_name, hash);
+ if (elem && elem->enable)
+ ret = 1;
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__dynamic_dbg_enabled_helper);
+
+static void set_all(bool enable)
+{
+ struct debug_name *e;
+ struct hlist_node *node;
+ int i;
+ long long enable_mask;
+
+ for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
+ if (module_table[i].first != NULL) {
+ hlist_for_each_entry(e, node, &module_table[i], hlist) {
+ e->enable = enable;
+ }
+ }
+ }
+ if (enable)
+ enable_mask = ULLONG_MAX;
+ else
+ enable_mask = 0;
+ dynamic_printk_enabled = enable_mask;
+ dynamic_printk_enabled2 = enable_mask;
+}
+
+static int disabled_hash(int i, bool first_table)
+{
+ struct debug_name *e;
+ struct hlist_node *node;
+
+ if (first_table) {
+ hlist_for_each_entry(e, node, &module_table[i], hlist) {
+ if (e->enable)
+ return 0;
+ }
+ } else {
+ hlist_for_each_entry(e, node, &module_table2[i], hlist2) {
+ if (e->enable)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static ssize_t pr_debug_write(struct file *file, const char __user *buf,
+ size_t length, loff_t *ppos)
+{
+ char *buffer, *s, *value_str, *setting_str;
+ int err, value;
+ struct debug_name *elem = NULL;
+ int all = 0;
+
+ if (length > PAGE_SIZE || length < 0)
+ return -EINVAL;
+
+ buffer = (char *)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ err = -EFAULT;
+ if (copy_from_user(buffer, buf, length))
+ goto out;
+
+ err = -EINVAL;
+ if (length < PAGE_SIZE)
+ buffer[length] = '\0';
+ else if (buffer[PAGE_SIZE-1])
+ goto out;
+
+ err = -EINVAL;
+ down(&debug_list_mutex);
+
+ if (strncmp("set", buffer, 3))
+ goto out_up;
+ s = buffer + 3;
+ setting_str = strsep(&s, "=");
+ if (s == NULL)
+ goto out_up;
+ setting_str = strstrip(setting_str);
+ value_str = strsep(&s, " ");
+ if (s == NULL)
+ goto out_up;
+ s = strstrip(s);
+ if (!strncmp(s, "all", 3))
+ all = 1;
+ else
+ elem = find_debug_module(s);
+ if (!strncmp(setting_str, "enable", 6)) {
+ value = !!simple_strtol(value_str, NULL, 10);
+ if (all) {
+ if (value) {
+ set_all(true);
+ num_enabled = nr_entries;
+ dynamic_enabled = DYNAMIC_ENABLED_ALL;
+ } else {
+ set_all(false);
+ num_enabled = 0;
+ dynamic_enabled = DYNAMIC_ENABLED_NONE;
+ }
+ err = 0;
+ } else {
+ if (elem) {
+ if (value && (elem->enable == 0)) {
+ dynamic_printk_enabled |=
+ (1LL << elem->hash1);
+ dynamic_printk_enabled2 |=
+ (1LL << elem->hash2);
+ elem->enable = 1;
+ num_enabled++;
+ dynamic_enabled = DYNAMIC_ENABLED_SOME;
+ err = 0;
+ } else if (!value && (elem->enable == 1)) {
+ elem->enable = 0;
+ num_enabled--;
+ if (disabled_hash(elem->hash1, true))
+ dynamic_printk_enabled &=
+ ~(1LL << elem->hash1);
+ if (disabled_hash(elem->hash2, false))
+ dynamic_printk_enabled2 &=
+ ~(1LL << elem->hash2);
+ if (num_enabled)
+ dynamic_enabled =
+ DYNAMIC_ENABLED_SOME;
+ else
+ dynamic_enabled =
+ DYNAMIC_ENABLED_NONE;
+ err = 0;
+ }
+ }
+ }
+ }
+ if (!err)
+ err = length;
+out_up:
+ up(&debug_list_mutex);
+out:
+ free_page((unsigned long)buffer);
+ return err;
+}
+
+static void *pr_debug_seq_start(struct seq_file *f, loff_t *pos)
+{
+ return (*pos < DEBUG_HASH_TABLE_SIZE) ? pos : NULL;
+}
+
+static void *pr_debug_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ (*pos)++;
+ if (*pos >= DEBUG_HASH_TABLE_SIZE)
+ return NULL;
+ return pos;
+}
+
+static void pr_debug_seq_stop(struct seq_file *s, void *v)
+{
+ /* Nothing to do */
+}
+
+static int pr_debug_seq_show(struct seq_file *s, void *v)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *elem;
+ unsigned int i = *(loff_t *) v;
+
+ rcu_read_lock();
+ head = &module_table[i];
+ hlist_for_each_entry_rcu(elem, node, head, hlist) {
+ seq_printf(s, "%s enabled=%d", elem->name, elem->enable);
+ seq_printf(s, "\n");
+ }
+ rcu_read_unlock();
+ return 0;
+}
+
+static struct seq_operations pr_debug_seq_ops = {
+ .start = pr_debug_seq_start,
+ .next = pr_debug_seq_next,
+ .stop = pr_debug_seq_stop,
+ .show = pr_debug_seq_show
+};
+
+static int pr_debug_open(struct inode *inode, struct file *filp)
+{
+ return seq_open(filp, &pr_debug_seq_ops);
+}
+
+static const struct file_operations pr_debug_operations = {
+ .open = pr_debug_open,
+ .read = seq_read,
+ .write = pr_debug_write,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+int __init dynamic_printk_init(void)
+{
+ struct dentry *dir, *file;
+ struct mod_debug *iter;
+ unsigned long value;
+
+ dir = debugfs_create_dir("dynamic_printk", NULL);
+ if (!dir)
+ return -ENOMEM;
+ file = debugfs_create_file("modules", 0644, dir, NULL,
+ &pr_debug_operations);
+ if (!file) {
+ debugfs_remove(dir);
+ return -ENOMEM;
+ }
+ for (value = (unsigned long)__start___verbose;
+ value < (unsigned long)__stop___verbose;
+ value += sizeof(struct mod_debug)) {
+ iter = (struct mod_debug *)value;
+ register_dynamic_debug_module(iter->modname,
+ iter->type,
+ iter->logical_modname,
+ iter->flag_names, iter->hash, iter->hash2);
+ }
+ return 0;
+}
+module_init(dynamic_printk_init);
+/* may want to move this earlier so we can get traces as early as possible */
+
+static int __init dynamic_printk_setup(char *str)
+{
+ if (str)
+ return -ENOENT;
+ set_all(true);
+ return 0;
+}
+/* Use early_param(), so we can get debug output as early as possible */
+early_param("dynamic_printk", dynamic_printk_setup);
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index 97e54b0..7fea304 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -65,7 +65,7 @@ void
struct nf_conntrack_expect *exp) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn);
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
/* PptpControlMessageType names */
const char *const pptp_msg_name[] = {
"UNKNOWN_MESSAGE",
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 8e44023..1e393cf 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -96,6 +96,14 @@ basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
modname_flags = $(if $(filter 1,$(words $(modname))),\
-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+#hash values
+ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\
+ -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))"
+else
+debug_flags =
+endif
+
_c_flags = $(KBUILD_CFLAGS) $(ccflags-y) $(CFLAGS_$(basetarget).o)
_a_flags = $(KBUILD_AFLAGS) $(asflags-y) $(AFLAGS_$(basetarget).o)
_cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F))
@@ -120,7 +128,8 @@ endif
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
$(__c_flags) $(modkern_cflags) \
- -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+ -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \
+ $(debug_flags)
a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
$(__a_flags) $(modkern_aflags)
diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile
index 4c324a1..0955995 100644
--- a/scripts/basic/Makefile
+++ b/scripts/basic/Makefile
@@ -9,7 +9,7 @@
# fixdep: Used to generate dependency information during build process
# docproc: Used in Documentation/DocBook
-hostprogs-y := fixdep docproc
+hostprogs-y := fixdep docproc hash
always := $(hostprogs-y)
# fixdep is needed to compile other host programs
diff --git a/scripts/basic/hash.c b/scripts/basic/hash.c
new file mode 100644
index 0000000..3299ad7
--- /dev/null
+++ b/scripts/basic/hash.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define DYNAMIC_DEBUG_HASH_BITS 6
+
+static const char *program;
+
+static void usage(void)
+{
+ printf("Usage: %s <djb2|r5> <modname>\n", program);
+ exit(1);
+}
+
+/* djb2 hashing algorithm by Dan Bernstein. From:
+ * http://www.cse.yorku.ca/~oz/hash.html
+ */
+
+unsigned int djb2_hash(char *str)
+{
+ unsigned long hash = 5381;
+ int c;
+
+ c = *str;
+ while (c) {
+ hash = ((hash << 5) + hash) + c;
+ c = *++str;
+ }
+ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
+}
+
+unsigned int r5_hash(char *str)
+{
+ unsigned long hash = 0;
+ int c;
+
+ c = *str;
+ while (c) {
+ hash = (hash + (c << 4) + (c >> 4)) * 11;
+ c = *++str;
+ }
+ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
+}
+
+int main(int argc, char *argv[])
+{
+ program = argv[0];
+
+ if (argc != 3)
+ usage();
+ if (!strcmp(argv[1], "djb2"))
+ printf("%d\n", djb2_hash(argv[2]));
+ else if (!strcmp(argv[1], "r5"))
+ printf("%d\n", r5_hash(argv[2]));
+ else
+ usage();
+ exit(0);
+}
+
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-12 20:46 ` Jason Baron
@ 2008-08-13 1:08 ` Greg KH
2008-08-13 1:16 ` Andrew Morton
2008-08-13 19:05 ` Jason Baron
2008-08-14 14:53 ` Greg KH
1 sibling, 2 replies; 29+ messages in thread
From: Greg KH @ 2008-08-13 1:08 UTC (permalink / raw)
To: Jason Baron; +Cc: Randy Dunlap, linux-kernel, akpm, joe, nick
On Tue, Aug 12, 2008 at 04:46:19PM -0400, Jason Baron wrote:
> On Tue, Aug 12, 2008 at 01:09:08PM -0700, Greg KH wrote:
> > So close, can I have a good changelog comment with the patch so people
> > know what it is when they look in the logs?
> >
> > Care to resend it with that?
> >
>
> Base infrastructure to enable per-module debug messages.
Ah, so close...
With this patch, I get the following build error:
CC [M] drivers/usb/gadget/u_ether.o
drivers/usb/gadget/u_ether.c: In function ‘gether_setup’:
drivers/usb/gadget/u_ether.c:787: error: ‘KBUILD_MODNAME’ undeclared (first use in this function)
drivers/usb/gadget/u_ether.c:787: error: (Each undeclared identifier is reported only once
drivers/usb/gadget/u_ether.c:787: error: for each function it appears in.)
drivers/usb/gadget/u_ether.c:787: error: unknown field ‘Usage’ specified in initializer
drivers/usb/gadget/u_ether.c:787: error: expected expression before ‘.’ token
drivers/usb/gadget/u_ether.c:787: error: initializer element is not constant
drivers/usb/gadget/u_ether.c:787: error: (near initialization for ‘descriptor.hash’)
drivers/usb/gadget/u_ether.c:787: error: ‘Usage’ undeclared (first use in this function)
drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ‘long long int’ and ‘char *’)
drivers/usb/gadget/u_ether.c:787: error: expected ‘)’ before ‘:’ token
drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ‘long long int’ and ‘char *’)
drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ‘long long int’ and ‘char *’)
drivers/usb/gadget/u_ether.c:787: error: expected ‘)’ before ‘:’ token
drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ‘long long int’ and ‘char *’)
drivers/usb/gadget/u_ether.c:787: error: expected ‘)’ before ‘:’ token
drivers/usb/gadget/u_ether.c:787: warning: passing argument 4 of ‘__dynamic_dbg_enabled_helper’ makes integer from pointer without a cast
drivers/usb/gadget/u_ether.c:787: error: expected ‘)’ before ‘KBUILD_MODNAME’
drivers/usb/gadget/u_ether.c:787: warning: too few arguments for format
make[1]: *** [drivers/usb/gadget/u_ether.o] Error 1
make: *** [_module_drivers/usb/gadget] Error 2
Did you try a simple 'make allmodconfig'?
Also, I cleaned it up a bit to make it pass checkpatch.pl and sparse,
doesn't anyone run these things anymore...
I've attached my fixed up version below.
Any ideas?
thanks,
greg k-h
From: Jason Baron <jbaron@redhat.com>
Date: Tue, 12 Aug 2008 16:46:19 -0400
Subject: driver core: basic infrastructure for per-module dynamic debug messages
To: Greg KH <greg@kroah.com>
Cc: Randy Dunlap <randy.dunlap@oracle.com>, linux-kernel@vger.kernel.org, akpm@linux-foundation.org, joe@perches.com, nick@nick-andrew.net
Message-ID: <20080812204619.GE6056@redhat.com>
Content-Disposition: inline
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.
Signed-off-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
Documentation/kernel-parameters.txt | 5
include/asm-generic/vmlinux.lds.h | 10
include/linux/device.h | 6
include/linux/dynamic_printk.h | 96 ++++++++
include/linux/kernel.h | 7
include/linux/module.h | 4
kernel/module.c | 22 +
lib/Kconfig.debug | 55 ++++
lib/Makefile | 2
lib/dynamic_printk.c | 412 ++++++++++++++++++++++++++++++++++++
net/netfilter/nf_conntrack_pptp.c | 2
scripts/Makefile.lib | 11
scripts/basic/Makefile | 2
scripts/basic/hash.c | 64 +++++
14 files changed, 692 insertions(+), 6 deletions(-)
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1675,6 +1675,11 @@ and is between 256 and 4096 characters.
autoconfiguration.
Ranges are in pairs (memory base and size).
+ dynamic_printk
+ Enables pr_debug()/dev_dbg() calls if
+ CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled. These can also
+ be switched on/off via <debugfs>/dynamic_printk/modules
+
print-fatal-signals=
[KNL] debug: print fatal signals
print-fatal-signals=1: print segfault info to
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -268,7 +268,15 @@
CPU_DISCARD(init.data) \
CPU_DISCARD(init.rodata) \
MEM_DISCARD(init.data) \
- MEM_DISCARD(init.rodata)
+ MEM_DISCARD(init.rodata) \
+ /* implement dynamic printk debug */ \
+ VMLINUX_SYMBOL(__start___verbose_strings) = .; \
+ *(__verbose_strings) \
+ VMLINUX_SYMBOL(__stop___verbose_strings) = .; \
+ . = ALIGN(8); \
+ VMLINUX_SYMBOL(__start___verbose) = .; \
+ *(__verbose) \
+ VMLINUX_SYMBOL(__stop___verbose) = .;
#define INIT_TEXT \
*(.init.text) \
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -538,7 +538,11 @@ extern const char *dev_driver_string(con
#define dev_info(dev, format, arg...) \
dev_printk(KERN_INFO , dev , format , ## arg)
-#ifdef DEBUG
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#define dev_dbg(dev, format, ...) do { \
+ dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
+ } while (0)
+#elif defined(DEBUG)
#define dev_dbg(dev, format, arg...) \
dev_printk(KERN_DEBUG , dev , format , ## arg)
#else
--- /dev/null
+++ b/include/linux/dynamic_printk.h
@@ -0,0 +1,96 @@
+#ifndef _DYNAMIC_PRINTK_H
+#define _DYNAMIC_PRINTK_H
+
+#include <linux/string.h>
+#include <linux/hash.h>
+
+#define DYNAMIC_DEBUG_HASH_BITS 6
+#define DEBUG_HASH_TABLE_SIZE (1 << DYNAMIC_DEBUG_HASH_BITS)
+
+#define TYPE_BOOLEAN 1
+
+#define DYNAMIC_ENABLED_ALL 0
+#define DYNAMIC_ENABLED_NONE 1
+#define DYNAMIC_ENABLED_SOME 2
+
+extern int dynamic_enabled;
+
+/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
+ * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
+ * use independent hash functions, to reduce the chance of false positives.
+ */
+extern long long dynamic_printk_enabled;
+extern long long dynamic_printk_enabled2;
+
+struct mod_debug {
+ char *modname;
+ char *logical_modname;
+ char *flag_names;
+ int type;
+ int hash;
+ int hash2;
+} __attribute__((aligned(8)));
+
+int register_dynamic_debug_module(char *mod_name, int type, char *share_name,
+ char *flags, int hash, int hash2);
+
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+extern int unregister_dynamic_debug_module(char *mod_name);
+extern int __dynamic_dbg_enabled_helper(char *modname, int type,
+ int value, int hash);
+
+#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ \
+ int ret = 0; \
+ if (unlikely((dynamic_printk_enabled & (1LL << DEBUG_HASH)) && \
+ (dynamic_printk_enabled2 & (1LL << DEBUG_HASH2)))) \
+ ret = __dynamic_dbg_enabled_helper(module, type, \
+ value, hash);\
+ ret; })
+
+#define dynamic_pr_debug(fmt, ...) do { \
+ static char mod_name[] \
+ __attribute__((section("__verbose_strings"))) \
+ = KBUILD_MODNAME; \
+ static struct mod_debug descriptor \
+ __used \
+ __attribute__((section("__verbose"), aligned(8))) = \
+ { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\
+ if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \
+ 0, 0, DEBUG_HASH)) \
+ printk(KERN_DEBUG KBUILD_MODNAME ":" fmt, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#define dynamic_dev_dbg(dev, format, ...) do { \
+ static char mod_name[] \
+ __attribute__((section("__verbose_strings"))) \
+ = KBUILD_MODNAME; \
+ static struct mod_debug descriptor \
+ __used \
+ __attribute__((section("__verbose"), aligned(8))) = \
+ { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\
+ if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \
+ 0, 0, DEBUG_HASH)) \
+ dev_printk(KERN_DEBUG, dev, \
+ KBUILD_MODNAME ": " format, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#else
+
+static inline int unregister_dynamic_debug_module(const char *mod_name)
+{
+ return 0;
+}
+static inline int __dynamic_dbg_enabled_helper(char *modname, int type,
+ int value, int hash)
+{
+ return 0;
+}
+
+#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ 0; })
+#define dynamic_pr_debug(fmt, ...) do { } while (0)
+#define dynamic_dev_dbg(dev, format, ...) do { } while (0)
+#endif
+
+#endif
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -16,6 +16,7 @@
#include <linux/log2.h>
#include <linux/typecheck.h>
#include <linux/ratelimit.h>
+#include <linux/dynamic_printk.h>
#include <asm/byteorder.h>
#include <asm/bug.h>
@@ -303,8 +304,12 @@ static inline char *pack_hex_byte(char *
#define pr_info(fmt, arg...) \
printk(KERN_INFO fmt, ##arg)
-#ifdef DEBUG
/* If you are writing a driver, please use dev_dbg instead */
+#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
+#define pr_debug(fmt, ...) do { \
+ dynamic_pr_debug(fmt, ##__VA_ARGS__); \
+ } while (0)
+#elif defined(DEBUG)
#define pr_debug(fmt, arg...) \
printk(KERN_DEBUG fmt, ##arg)
#else
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -346,6 +346,10 @@ struct module
struct module_ref ref[NR_CPUS];
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ struct mod_debug *start_verbose;
+ unsigned int num_verbose;
+#endif
};
#ifndef MODULE_ARCH_INIT
#define MODULE_ARCH_INIT {}
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -784,6 +784,7 @@ sys_delete_module(const char __user *nam
mutex_lock(&module_mutex);
/* Store the name of the last unloaded module for diagnostic purposes */
strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
+ unregister_dynamic_debug_module(mod->name);
free_module(mod);
out:
@@ -1831,6 +1832,9 @@ static struct module *load_module(void _
#endif
unsigned int markersindex;
unsigned int markersstringsindex;
+ unsigned int verboseindex;
+ struct mod_debug *iter;
+ unsigned long value;
struct module *mod;
long err = 0;
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -2117,6 +2121,7 @@ static struct module *load_module(void _
markersindex = find_sec(hdr, sechdrs, secstrings, "__markers");
markersstringsindex = find_sec(hdr, sechdrs, secstrings,
"__markers_strings");
+ verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose");
/* Now do relocations. */
for (i = 1; i < hdr->e_shnum; i++) {
@@ -2144,6 +2149,11 @@ static struct module *load_module(void _
mod->num_markers =
sechdrs[markersindex].sh_size / sizeof(*mod->markers);
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ mod->start_verbose = (void *)sechdrs[verboseindex].sh_addr;
+ mod->num_verbose = sechdrs[verboseindex].sh_size /
+ sizeof(*mod->start_verbose);
+#endif
/* Find duplicate symbols */
err = verify_export_symbols(mod);
@@ -2167,6 +2177,18 @@ static struct module *load_module(void _
marker_update_probe_range(mod->markers,
mod->markers + mod->num_markers);
#endif
+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+ for (value = (unsigned long)mod->start_verbose;
+ value < (unsigned long)mod->start_verbose +
+ (unsigned long)(mod->num_verbose * sizeof(struct mod_debug));
+ value += sizeof(struct mod_debug)) {
+ iter = (struct mod_debug *)value;
+ register_dynamic_debug_module(iter->modname,
+ iter->type,
+ iter->logical_modname,
+ iter->flag_names, iter->hash, iter->hash2);
+ }
+#endif
err = module_finalize(hdr, sechdrs, mod);
if (err < 0)
goto cleanup;
--- /dev/null
+++ b/lib/dynamic_printk.c
@@ -0,0 +1,412 @@
+/*
+ * lib/dynamic_printk.c
+ *
+ * make pr_debug()/dev_dbg() calls runtime configurable based upon their
+ * their source module.
+ *
+ * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+
+extern struct mod_debug __start___verbose[];
+extern struct mod_debug __stop___verbose[];
+
+struct debug_name {
+ struct hlist_node hlist;
+ struct hlist_node hlist2;
+ int hash1;
+ int hash2;
+ char *name;
+ int enable;
+ int type;
+};
+
+static int nr_entries;
+static int num_enabled;
+int dynamic_enabled = DYNAMIC_ENABLED_NONE;
+static struct hlist_head module_table[DEBUG_HASH_TABLE_SIZE] =
+ { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
+static struct hlist_head module_table2[DEBUG_HASH_TABLE_SIZE] =
+ { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
+static DECLARE_MUTEX(debug_list_mutex);
+
+/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
+ * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
+ * use independent hash functions, to reduce the chance of false positives.
+ */
+long long dynamic_printk_enabled;
+EXPORT_SYMBOL_GPL(dynamic_printk_enabled);
+long long dynamic_printk_enabled2;
+EXPORT_SYMBOL_GPL(dynamic_printk_enabled2);
+
+/* returns the debug module pointer. */
+static struct debug_name *find_debug_module(char *module_name)
+{
+ int i;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *element;
+
+ element = NULL;
+ for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
+ head = &module_table[i];
+ hlist_for_each_entry_rcu(element, node, head, hlist)
+ if (!strcmp(element->name, module_name))
+ return element;
+ }
+ return NULL;
+}
+
+/* returns the debug module pointer. */
+static struct debug_name *find_debug_module_hash(char *module_name, int hash)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *element;
+
+ element = NULL;
+ head = &module_table[hash];
+ hlist_for_each_entry_rcu(element, node, head, hlist)
+ if (!strcmp(element->name, module_name))
+ return element;
+ return NULL;
+}
+
+/* caller must hold mutex*/
+static int __add_debug_module(char *mod_name, int hash, int hash2)
+{
+ struct debug_name *new;
+ char *module_name;
+ int ret = 0;
+
+ if (find_debug_module(mod_name)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ module_name = kmalloc(strlen(mod_name) + 1, GFP_KERNEL);
+ if (!module_name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ module_name = strcpy(module_name, mod_name);
+ module_name[strlen(mod_name)] = '\0';
+ new = kzalloc(sizeof(struct debug_name), GFP_KERNEL);
+ if (!new) {
+ kfree(module_name);
+ ret = -ENOMEM;
+ goto out;
+ }
+ INIT_HLIST_NODE(&new->hlist);
+ INIT_HLIST_NODE(&new->hlist2);
+ new->name = module_name;
+ new->hash1 = hash;
+ new->hash2 = hash2;
+ hlist_add_head_rcu(&new->hlist, &module_table[hash]);
+ hlist_add_head_rcu(&new->hlist2, &module_table2[hash2]);
+ nr_entries++;
+out:
+ return ret;
+}
+
+int unregister_dynamic_debug_module(char *mod_name)
+{
+ struct debug_name *element;
+ int ret = 0;
+
+ down(&debug_list_mutex);
+ element = find_debug_module(mod_name);
+ if (!element) {
+ ret = -EINVAL;
+ goto out;
+ }
+ hlist_del_rcu(&element->hlist);
+ hlist_del_rcu(&element->hlist2);
+ synchronize_rcu();
+ kfree(element->name);
+ if (element->enable)
+ num_enabled--;
+ kfree(element);
+ nr_entries--;
+out:
+ up(&debug_list_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(unregister_dynamic_debug_module);
+
+int register_dynamic_debug_module(char *mod_name, int type, char *share_name,
+ char *flags, int hash, int hash2)
+{
+ struct debug_name *elem;
+ int ret = 0;
+
+ down(&debug_list_mutex);
+ elem = find_debug_module(mod_name);
+ if (!elem) {
+ if (__add_debug_module(mod_name, hash, hash2))
+ goto out;
+ elem = find_debug_module(mod_name);
+ if (dynamic_enabled == DYNAMIC_ENABLED_ALL &&
+ !strcmp(mod_name, share_name)) {
+ elem->enable = true;
+ num_enabled++;
+ }
+ }
+ elem->type |= type;
+out:
+ up(&debug_list_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_dynamic_debug_module);
+
+int __dynamic_dbg_enabled_helper(char *mod_name, int type, int value, int hash)
+{
+ struct debug_name *elem;
+ int ret = 0;
+
+ if (dynamic_enabled == DYNAMIC_ENABLED_ALL)
+ return 1;
+ rcu_read_lock();
+ elem = find_debug_module_hash(mod_name, hash);
+ if (elem && elem->enable)
+ ret = 1;
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__dynamic_dbg_enabled_helper);
+
+static void set_all(bool enable)
+{
+ struct debug_name *e;
+ struct hlist_node *node;
+ int i;
+ long long enable_mask;
+
+ for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
+ if (module_table[i].first != NULL) {
+ hlist_for_each_entry(e, node, &module_table[i], hlist) {
+ e->enable = enable;
+ }
+ }
+ }
+ if (enable)
+ enable_mask = ULLONG_MAX;
+ else
+ enable_mask = 0;
+ dynamic_printk_enabled = enable_mask;
+ dynamic_printk_enabled2 = enable_mask;
+}
+
+static int disabled_hash(int i, bool first_table)
+{
+ struct debug_name *e;
+ struct hlist_node *node;
+
+ if (first_table) {
+ hlist_for_each_entry(e, node, &module_table[i], hlist) {
+ if (e->enable)
+ return 0;
+ }
+ } else {
+ hlist_for_each_entry(e, node, &module_table2[i], hlist2) {
+ if (e->enable)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static ssize_t pr_debug_write(struct file *file, const char __user *buf,
+ size_t length, loff_t *ppos)
+{
+ char *buffer, *s, *value_str, *setting_str;
+ int err, value;
+ struct debug_name *elem = NULL;
+ int all = 0;
+
+ if (length > PAGE_SIZE || length < 0)
+ return -EINVAL;
+
+ buffer = (char *)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ err = -EFAULT;
+ if (copy_from_user(buffer, buf, length))
+ goto out;
+
+ err = -EINVAL;
+ if (length < PAGE_SIZE)
+ buffer[length] = '\0';
+ else if (buffer[PAGE_SIZE-1])
+ goto out;
+
+ err = -EINVAL;
+ down(&debug_list_mutex);
+
+ if (strncmp("set", buffer, 3))
+ goto out_up;
+ s = buffer + 3;
+ setting_str = strsep(&s, "=");
+ if (s == NULL)
+ goto out_up;
+ setting_str = strstrip(setting_str);
+ value_str = strsep(&s, " ");
+ if (s == NULL)
+ goto out_up;
+ s = strstrip(s);
+ if (!strncmp(s, "all", 3))
+ all = 1;
+ else
+ elem = find_debug_module(s);
+ if (!strncmp(setting_str, "enable", 6)) {
+ value = !!simple_strtol(value_str, NULL, 10);
+ if (all) {
+ if (value) {
+ set_all(true);
+ num_enabled = nr_entries;
+ dynamic_enabled = DYNAMIC_ENABLED_ALL;
+ } else {
+ set_all(false);
+ num_enabled = 0;
+ dynamic_enabled = DYNAMIC_ENABLED_NONE;
+ }
+ err = 0;
+ } else {
+ if (elem) {
+ if (value && (elem->enable == 0)) {
+ dynamic_printk_enabled |=
+ (1LL << elem->hash1);
+ dynamic_printk_enabled2 |=
+ (1LL << elem->hash2);
+ elem->enable = 1;
+ num_enabled++;
+ dynamic_enabled = DYNAMIC_ENABLED_SOME;
+ err = 0;
+ } else if (!value && (elem->enable == 1)) {
+ elem->enable = 0;
+ num_enabled--;
+ if (disabled_hash(elem->hash1, true))
+ dynamic_printk_enabled &=
+ ~(1LL << elem->hash1);
+ if (disabled_hash(elem->hash2, false))
+ dynamic_printk_enabled2 &=
+ ~(1LL << elem->hash2);
+ if (num_enabled)
+ dynamic_enabled =
+ DYNAMIC_ENABLED_SOME;
+ else
+ dynamic_enabled =
+ DYNAMIC_ENABLED_NONE;
+ err = 0;
+ }
+ }
+ }
+ }
+ if (!err)
+ err = length;
+out_up:
+ up(&debug_list_mutex);
+out:
+ free_page((unsigned long)buffer);
+ return err;
+}
+
+static void *pr_debug_seq_start(struct seq_file *f, loff_t *pos)
+{
+ return (*pos < DEBUG_HASH_TABLE_SIZE) ? pos : NULL;
+}
+
+static void *pr_debug_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ (*pos)++;
+ if (*pos >= DEBUG_HASH_TABLE_SIZE)
+ return NULL;
+ return pos;
+}
+
+static void pr_debug_seq_stop(struct seq_file *s, void *v)
+{
+ /* Nothing to do */
+}
+
+static int pr_debug_seq_show(struct seq_file *s, void *v)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct debug_name *elem;
+ unsigned int i = *(loff_t *) v;
+
+ rcu_read_lock();
+ head = &module_table[i];
+ hlist_for_each_entry_rcu(elem, node, head, hlist) {
+ seq_printf(s, "%s enabled=%d", elem->name, elem->enable);
+ seq_printf(s, "\n");
+ }
+ rcu_read_unlock();
+ return 0;
+}
+
+static struct seq_operations pr_debug_seq_ops = {
+ .start = pr_debug_seq_start,
+ .next = pr_debug_seq_next,
+ .stop = pr_debug_seq_stop,
+ .show = pr_debug_seq_show
+};
+
+static int pr_debug_open(struct inode *inode, struct file *filp)
+{
+ return seq_open(filp, &pr_debug_seq_ops);
+}
+
+static const struct file_operations pr_debug_operations = {
+ .open = pr_debug_open,
+ .read = seq_read,
+ .write = pr_debug_write,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int __init dynamic_printk_init(void)
+{
+ struct dentry *dir, *file;
+ struct mod_debug *iter;
+ unsigned long value;
+
+ dir = debugfs_create_dir("dynamic_printk", NULL);
+ if (!dir)
+ return -ENOMEM;
+ file = debugfs_create_file("modules", 0644, dir, NULL,
+ &pr_debug_operations);
+ if (!file) {
+ debugfs_remove(dir);
+ return -ENOMEM;
+ }
+ for (value = (unsigned long)__start___verbose;
+ value < (unsigned long)__stop___verbose;
+ value += sizeof(struct mod_debug)) {
+ iter = (struct mod_debug *)value;
+ register_dynamic_debug_module(iter->modname,
+ iter->type,
+ iter->logical_modname,
+ iter->flag_names, iter->hash, iter->hash2);
+ }
+ return 0;
+}
+module_init(dynamic_printk_init);
+/* may want to move this earlier so we can get traces as early as possible */
+
+static int __init dynamic_printk_setup(char *str)
+{
+ if (str)
+ return -ENOENT;
+ set_all(true);
+ return 0;
+}
+/* Use early_param(), so we can get debug output as early as possible */
+early_param("dynamic_printk", dynamic_printk_setup);
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -735,6 +735,61 @@ config FIREWIRE_OHCI_REMOTE_DMA
If unsure, say N.
+config DYNAMIC_PRINTK_DEBUG
+ bool "Enable dynamic printk() call support"
+ default n
+ depends on PRINTK
+ select PRINTK_DEBUG
+ help
+
+ Compiles debug level messages into the kernel, which would not
+ otherwise be available at runtime. These messages can then be
+ enabled/disabled on a per module basis. This mechanism implicitly
+ enables all pr_debug() and dev_dbg() calls. The impact of this
+ compile option is a larger kernel text size of about 2%.
+
+ Usage:
+
+ Dynamic debugging is controlled by the debugfs file,
+ dynamic_printk/modules. This file contains a list of the modules that
+ can be enabled. The format of the file is the module name, followed
+ by a set of flags that can be enabled. The first flag is always the
+ 'enabled' flag. For example:
+
+ <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
+
+ From a live system:
+
+ snd_hda_intel enabled=0
+ fixup enabled=0
+ 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.
+
source "samples/Kconfig"
source "lib/Kconfig.kgdb"
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -80,6 +80,8 @@ obj-$(CONFIG_HAVE_LMB) += lmb.o
obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) += syscall.o
+obj-$(CONFIG_DYNAMIC_PRINTK_DEBUG) += dynamic_printk.o
+
hostprogs-y := gen_crc32table
clean-files := crc32table.h
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -65,7 +65,7 @@ void
struct nf_conntrack_expect *exp) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn);
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
/* PptpControlMessageType names */
const char *const pptp_msg_name[] = {
"UNKNOWN_MESSAGE",
--- /dev/null
+++ b/scripts/basic/hash.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define DYNAMIC_DEBUG_HASH_BITS 6
+
+static const char *program;
+
+static void usage(void)
+{
+ printf("Usage: %s <djb2|r5> <modname>\n", program);
+ exit(1);
+}
+
+/* djb2 hashing algorithm by Dan Bernstein. From:
+ * http://www.cse.yorku.ca/~oz/hash.html
+ */
+
+unsigned int djb2_hash(char *str)
+{
+ unsigned long hash = 5381;
+ int c;
+
+ c = *str;
+ while (c) {
+ hash = ((hash << 5) + hash) + c;
+ c = *++str;
+ }
+ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
+}
+
+unsigned int r5_hash(char *str)
+{
+ unsigned long hash = 0;
+ int c;
+
+ c = *str;
+ while (c) {
+ hash = (hash + (c << 4) + (c >> 4)) * 11;
+ c = *++str;
+ }
+ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
+}
+
+int main(int argc, char *argv[])
+{
+ program = argv[0];
+
+ if (argc != 3)
+ usage();
+ if (!strcmp(argv[1], "djb2"))
+ printf("%d\n", djb2_hash(argv[2]));
+ else if (!strcmp(argv[1], "r5"))
+ printf("%d\n", r5_hash(argv[2]));
+ else
+ usage();
+ exit(0);
+}
+
--- a/scripts/basic/Makefile
+++ b/scripts/basic/Makefile
@@ -9,7 +9,7 @@
# fixdep: Used to generate dependency information during build process
# docproc: Used in Documentation/DocBook
-hostprogs-y := fixdep docproc
+hostprogs-y := fixdep docproc hash
always := $(hostprogs-y)
# fixdep is needed to compile other host programs
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -96,6 +96,14 @@ basename_flags = -D"KBUILD_BASENAME=KBUI
modname_flags = $(if $(filter 1,$(words $(modname))),\
-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+#hash values
+ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
+debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\
+ -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))"
+else
+debug_flags =
+endif
+
orig_c_flags = $(KBUILD_CFLAGS) $(ccflags-y) $(CFLAGS_$(basetarget).o)
_c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
_a_flags = $(KBUILD_AFLAGS) $(asflags-y) $(AFLAGS_$(basetarget).o)
@@ -121,7 +129,8 @@ endif
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
$(__c_flags) $(modkern_cflags) \
- -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+ -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \
+ $(debug_flags)
a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
$(__a_flags) $(modkern_aflags)
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-13 1:08 ` Greg KH
@ 2008-08-13 1:16 ` Andrew Morton
2008-08-13 3:38 ` Greg KH
2008-08-13 19:05 ` Jason Baron
1 sibling, 1 reply; 29+ messages in thread
From: Andrew Morton @ 2008-08-13 1:16 UTC (permalink / raw)
To: Greg KH; +Cc: jbaron, randy.dunlap, linux-kernel, joe, nick, Sam Ravnborg
On Tue, 12 Aug 2008 18:08:04 -0700
Greg KH <greg@kroah.com> wrote:
> On Tue, Aug 12, 2008 at 04:46:19PM -0400, Jason Baron wrote:
> > On Tue, Aug 12, 2008 at 01:09:08PM -0700, Greg KH wrote:
> > > So close, can I have a good changelog comment with the patch so people
> > > know what it is when they look in the logs?
> > >
> > > Care to resend it with that?
> > >
> >
> > Base infrastructure to enable per-module debug messages.
>
> Ah, so close...
>
> With this patch, I get the following build error:
>
> CC [M] drivers/usb/gadget/u_ether.o
> drivers/usb/gadget/u_ether.c: In function ___gether_setup___:
> drivers/usb/gadget/u_ether.c:787: error: ___KBUILD_MODNAME___ undeclared (first use in this function)
> drivers/usb/gadget/u_ether.c:787: error: (Each undeclared identifier is reported only once
> drivers/usb/gadget/u_ether.c:787: error: for each function it appears in.)
> drivers/usb/gadget/u_ether.c:787: error: unknown field ___Usage___ specified in initializer
> drivers/usb/gadget/u_ether.c:787: error: expected expression before ___.___ token
> drivers/usb/gadget/u_ether.c:787: error: initializer element is not constant
> drivers/usb/gadget/u_ether.c:787: error: (near initialization for ___descriptor.hash___)
> drivers/usb/gadget/u_ether.c:787: error: ___Usage___ undeclared (first use in this function)
> drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ___long long int___ and ___char *___)
> drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ___long long int___ and ___char *___)
> drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ___long long int___ and ___char *___)
> drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ___long long int___ and ___char *___)
> drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> drivers/usb/gadget/u_ether.c:787: warning: passing argument 4 of _____dynamic_dbg_enabled_helper___ makes integer from pointer without a cast
> drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___KBUILD_MODNAME___
(lol at gcc crap)
> drivers/usb/gadget/u_ether.c:787: warning: too few arguments for format
argh, not that again. We had this with a patch from Jesse a while
back, which I fixed thusly:
From: Andrew Morton <akpm@linux-foundation.org>
alpha:
CC [M] drivers/usb/gadget/u_ether.o
In file included from include/asm/dma-mapping.h:7,
from include/linux/dma-mapping.h:52,
from include/linux/dmaengine.h:29,
from include/linux/skbuff.h:29,
from include/linux/if_ether.h:114,
from include/linux/etherdevice.h:27,
from drivers/usb/gadget/u_ether.c:29:
include/linux/pci.h: In function 'pci_register_driver':
include/linux/pci.h:673: error: 'KBUILD_MODNAME' undeclared (first use in this function)
include/linux/pci.h:673: error: (Each undeclared identifier is reported only once
include/linux/pci.h:673: error: for each function it appears in.)
Sam says:
The problem is that u_ether.o is used by two modules so when we build it
KBUILD_MODNAME is not defined because kbuild does not know what value to
use.
And in pci.h we have the following inline:
static inline int __must_check pci_register_driver(struct pci_driver *driver)
{
return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
}
And alpha uses dma-mapping.h to nullify a number of functions that seem to
require something from pci.h.
Making it a macro seems to fix this.
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Sam Ravnborg <sam@ravnborg.org>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
include/linux/pci.h | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff -puN include/linux/pci.h~pci-make-pci_register_driver-a-macro include/linux/pci.h
--- a/include/linux/pci.h~pci-make-pci_register_driver-a-macro
+++ a/include/linux/pci.h
@@ -680,10 +680,12 @@ void pci_enable_bridges(struct pci_bus *
/* Proper probing supporting hot-pluggable devices */
int __must_check __pci_register_driver(struct pci_driver *, struct module *,
const char *mod_name);
-static inline int __must_check pci_register_driver(struct pci_driver *driver)
-{
- return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
-}
+
+/*
+ * pci_register_driver must be a macro so that KBUILD_MODNAME can be expanded
+ */
+#define pci_register_driver(driver) \
+ __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
void pci_unregister_driver(struct pci_driver *dev);
void pci_remove_behind_bridge(struct pci_dev *dev);
_
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-13 1:16 ` Andrew Morton
@ 2008-08-13 3:38 ` Greg KH
2008-08-13 20:00 ` Sam Ravnborg
0 siblings, 1 reply; 29+ messages in thread
From: Greg KH @ 2008-08-13 3:38 UTC (permalink / raw)
To: Andrew Morton, Sam Ravnborg; +Cc: jbaron, randy.dunlap, linux-kernel, joe, nick
On Tue, Aug 12, 2008 at 06:16:53PM -0700, Andrew Morton wrote:
> On Tue, 12 Aug 2008 18:08:04 -0700
> Greg KH <greg@kroah.com> wrote:
>
> > On Tue, Aug 12, 2008 at 04:46:19PM -0400, Jason Baron wrote:
> > > On Tue, Aug 12, 2008 at 01:09:08PM -0700, Greg KH wrote:
> > > > So close, can I have a good changelog comment with the patch so people
> > > > know what it is when they look in the logs?
> > > >
> > > > Care to resend it with that?
> > > >
> > >
> > > Base infrastructure to enable per-module debug messages.
> >
> > Ah, so close...
> >
> > With this patch, I get the following build error:
> >
> > CC [M] drivers/usb/gadget/u_ether.o
> > drivers/usb/gadget/u_ether.c: In function ___gether_setup___:
> > drivers/usb/gadget/u_ether.c:787: error: ___KBUILD_MODNAME___ undeclared (first use in this function)
> > drivers/usb/gadget/u_ether.c:787: error: (Each undeclared identifier is reported only once
> > drivers/usb/gadget/u_ether.c:787: error: for each function it appears in.)
> > drivers/usb/gadget/u_ether.c:787: error: unknown field ___Usage___ specified in initializer
> > drivers/usb/gadget/u_ether.c:787: error: expected expression before ___.___ token
> > drivers/usb/gadget/u_ether.c:787: error: initializer element is not constant
> > drivers/usb/gadget/u_ether.c:787: error: (near initialization for ___descriptor.hash___)
> > drivers/usb/gadget/u_ether.c:787: error: ___Usage___ undeclared (first use in this function)
> > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ___long long int___ and ___char *___)
> > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ___long long int___ and ___char *___)
> > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ___long long int___ and ___char *___)
> > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ___long long int___ and ___char *___)
> > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > drivers/usb/gadget/u_ether.c:787: warning: passing argument 4 of _____dynamic_dbg_enabled_helper___ makes integer from pointer without a cast
> > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___KBUILD_MODNAME___
>
> (lol at gcc crap)
>
> > drivers/usb/gadget/u_ether.c:787: warning: too few arguments for format
>
> argh, not that again. We had this with a patch from Jesse a while
> back, which I fixed thusly:
<patch moving KBUILD_MODNAME from a inline function to a macro snipped>
Yeah, I remember that too, but in this case, KBUILD_MODNAME is being
used in a macro, not an inline function, the exact opposite.
Sam, any ideas here? I'll bounce the original patch at you if you
missed it last time.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-13 1:08 ` Greg KH
2008-08-13 1:16 ` Andrew Morton
@ 2008-08-13 19:05 ` Jason Baron
1 sibling, 0 replies; 29+ messages in thread
From: Jason Baron @ 2008-08-13 19:05 UTC (permalink / raw)
To: Greg KH; +Cc: Randy Dunlap, linux-kernel, akpm, joe, nick, sam
On Tue, Aug 12, 2008 at 06:08:04PM -0700, Greg KH wrote:
> On Tue, Aug 12, 2008 at 04:46:19PM -0400, Jason Baron wrote:
> > On Tue, Aug 12, 2008 at 01:09:08PM -0700, Greg KH wrote:
> > > So close, can I have a good changelog comment with the patch so people
> > > know what it is when they look in the logs?
> > >
> > > Care to resend it with that?
> > >
> >
> > Base infrastructure to enable per-module debug messages.
>
> Ah, so close...
>
> With this patch, I get the following build error:
>
> CC [M] drivers/usb/gadget/u_ether.o
> drivers/usb/gadget/u_ether.c: In function ‘gether_setup’:
> drivers/usb/gadget/u_ether.c:787: error: ‘KBUILD_MODNAME’ undeclared (first use in this function)
> drivers/usb/gadget/u_ether.c:787: error: (Each undeclared identifier is reported only once
> drivers/usb/gadget/u_ether.c:787: error: for each function it appears in.)
> drivers/usb/gadget/u_ether.c:787: error: unknown field ‘Usage’ specified in initializer
> drivers/usb/gadget/u_ether.c:787: error: expected expression before ‘.’ token
> drivers/usb/gadget/u_ether.c:787: error: initializer element is not constant
> drivers/usb/gadget/u_ether.c:787: error: (near initialization for ‘descriptor.hash’)
> drivers/usb/gadget/u_ether.c:787: error: ‘Usage’ undeclared (first use in this function)
> drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ‘long long int’ and ‘char *’)
> drivers/usb/gadget/u_ether.c:787: error: expected ‘)’ before ‘:’ token
> drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ‘long long int’ and ‘char *’)
> drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ‘long long int’ and ‘char *’)
> drivers/usb/gadget/u_ether.c:787: error: expected ‘)’ before ‘:’ token
> drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ‘long long int’ and ‘char *’)
> drivers/usb/gadget/u_ether.c:787: error: expected ‘)’ before ‘:’ token
> drivers/usb/gadget/u_ether.c:787: warning: passing argument 4 of ‘__dynamic_dbg_enabled_helper’ makes integer from pointer without a cast
> drivers/usb/gadget/u_ether.c:787: error: expected ‘)’ before ‘KBUILD_MODNAME’
> drivers/usb/gadget/u_ether.c:787: warning: too few arguments for format
> make[1]: *** [drivers/usb/gadget/u_ether.o] Error 1
> make: *** [_module_drivers/usb/gadget] Error 2
>
>
> Did you try a simple 'make allmodconfig'?
>
> Also, I cleaned it up a bit to make it pass checkpatch.pl and sparse,
> doesn't anyone run these things anymore...
>
> I've attached my fixed up version below.
>
> Any ideas?
>
I was working on an older kernel and so i didn't see this error.
There seem to be a couple of issues here.
First, KBUILD_MODNAME is not defined during the compile of u_ether.c because
it is included from multiple sources. It seems that when there are multiple
sources "modname" is set to a string of all the source names with spaces in
between. So something used in foo and bar looks like: "foo bar". From
scripts/Makefile.lib:
# Note: It's possible that one object gets potentially linked into more
# than one module. In that case KBUILD_MODNAME will be set to foo_bar,
# where foo and bar are the name of the modules.
name-fix = $(subst $(comma),_,$(subst -,_,$1))
basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
modname_flags = $(if $(filter 1,$(words $(modname))),\
-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
.
.
.
So, the comment says that the KBUILD_MODNAME should be set to "foo_bar" if
its included from multiple files...however, the modname_flags definition is not
doing that. In fact, if there are multiple sources its simply setting a
NULL modname_flag. This issue is independent of the patchset I posted, and
probably is best fixed separately. A patch which resolves this issue:
Signed-off-by: Jason Baron <jbaron@redhat.com>
---
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index b4ca38a..639d5dc 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -94,7 +94,8 @@ obj-dirs := $(addprefix $(obj)/,$(obj-dirs))
name-fix = $(subst $(comma),_,$(subst -,_,$1))
basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
modname_flags = $(if $(filter 1,$(words $(modname))),\
- -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+ -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))",\
+ -D"KBUILD_MODNAME=KBUILD_STR($(subst $(space),_,$(call name-fix,$(modname))))")
#hash values
ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
The second issue is then that the hash functions that i introduced don't like
these spaces either. So on top of the patch set i posted please add the patch
below. The kernel should then compile. I tested this on the 'linux-next' tree,
which did not boot on the system i was using, but i'm not sure it was related
to this change.
thanks,
-Jason
Signed-off-by: Jason Baron <jbaron@redhat.com>
---
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 639d5dc..3b5455b 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -99,8 +99,8 @@ modname_flags = $(if $(filter 1,$(words $(modname))),\
#hash values
ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
-debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\
- -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))"
+debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(subst $(space),_,$(modname)))"\
+ -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(subst $(space),_,$(modname)))"
else
debug_flags =
endif
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-13 3:38 ` Greg KH
@ 2008-08-13 20:00 ` Sam Ravnborg
2008-08-13 22:49 ` jbaron
2008-08-13 23:54 ` Greg KH
0 siblings, 2 replies; 29+ messages in thread
From: Sam Ravnborg @ 2008-08-13 20:00 UTC (permalink / raw)
To: Greg KH; +Cc: Andrew Morton, jbaron, randy.dunlap, linux-kernel, joe, nick
On Tue, Aug 12, 2008 at 08:38:59PM -0700, Greg KH wrote:
> On Tue, Aug 12, 2008 at 06:16:53PM -0700, Andrew Morton wrote:
> > On Tue, 12 Aug 2008 18:08:04 -0700
> > Greg KH <greg@kroah.com> wrote:
> >
> > > On Tue, Aug 12, 2008 at 04:46:19PM -0400, Jason Baron wrote:
> > > > On Tue, Aug 12, 2008 at 01:09:08PM -0700, Greg KH wrote:
> > > > > So close, can I have a good changelog comment with the patch so people
> > > > > know what it is when they look in the logs?
> > > > >
> > > > > Care to resend it with that?
> > > > >
> > > >
> > > > Base infrastructure to enable per-module debug messages.
> > >
> > > Ah, so close...
> > >
> > > With this patch, I get the following build error:
> > >
> > > CC [M] drivers/usb/gadget/u_ether.o
> > > drivers/usb/gadget/u_ether.c: In function ___gether_setup___:
> > > drivers/usb/gadget/u_ether.c:787: error: ___KBUILD_MODNAME___ undeclared (first use in this function)
> > > drivers/usb/gadget/u_ether.c:787: error: (Each undeclared identifier is reported only once
> > > drivers/usb/gadget/u_ether.c:787: error: for each function it appears in.)
> > > drivers/usb/gadget/u_ether.c:787: error: unknown field ___Usage___ specified in initializer
> > > drivers/usb/gadget/u_ether.c:787: error: expected expression before ___.___ token
> > > drivers/usb/gadget/u_ether.c:787: error: initializer element is not constant
> > > drivers/usb/gadget/u_ether.c:787: error: (near initialization for ___descriptor.hash___)
> > > drivers/usb/gadget/u_ether.c:787: error: ___Usage___ undeclared (first use in this function)
> > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ___long long int___ and ___char *___)
> > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ___long long int___ and ___char *___)
> > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ___long long int___ and ___char *___)
> > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ___long long int___ and ___char *___)
> > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > > drivers/usb/gadget/u_ether.c:787: warning: passing argument 4 of _____dynamic_dbg_enabled_helper___ makes integer from pointer without a cast
> > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___KBUILD_MODNAME___
> >
> > (lol at gcc crap)
> >
> > > drivers/usb/gadget/u_ether.c:787: warning: too few arguments for format
> >
> > argh, not that again. We had this with a patch from Jesse a while
> > back, which I fixed thusly:
>
> <patch moving KBUILD_MODNAME from a inline function to a macro snipped>
>
> Yeah, I remember that too, but in this case, KBUILD_MODNAME is being
> used in a macro, not an inline function, the exact opposite.
>
> Sam, any ideas here? I'll bounce the original patch at you if you
> missed it last time.
I have not looked into the particular error but what happens is
that u_ether.o is used by more than one module so kbuild does
not know what value to assign the KBUILD_MODNAME and therefore
decide not to assign KBUILD_MODNAME at all.
And because any usage of KBUILD_MODNAME is anyway flawed in u_ether.c
as we do not know for what module it is being used it makes sense for
kbuild to do so.
The above error happens because u_ether.c uses something that require KBUILD_MODNAME
to be define.
So the correct fix is to avid usage of this macro in the source.
Note: The old error Andrew mentions was caused by alpha indirectly
pulling in a inline function that used KBUILD_MODNAME - something
that did not happen on the other architectures.
Sam
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-13 20:00 ` Sam Ravnborg
@ 2008-08-13 22:49 ` jbaron
2008-08-13 23:54 ` Greg KH
1 sibling, 0 replies; 29+ messages in thread
From: jbaron @ 2008-08-13 22:49 UTC (permalink / raw)
To: Sam Ravnborg
Cc: Greg KH, Andrew Morton, randy.dunlap, linux-kernel, joe, nick
On Wed, Aug 13, 2008 at 10:00:47PM +0200, Sam Ravnborg wrote:
> On Tue, Aug 12, 2008 at 08:38:59PM -0700, Greg KH wrote:
> > On Tue, Aug 12, 2008 at 06:16:53PM -0700, Andrew Morton wrote:
> > > On Tue, 12 Aug 2008 18:08:04 -0700
> > > Greg KH <greg@kroah.com> wrote:
> > >
> > > > On Tue, Aug 12, 2008 at 04:46:19PM -0400, Jason Baron wrote:
> > > > > On Tue, Aug 12, 2008 at 01:09:08PM -0700, Greg KH wrote:
> > > > > > So close, can I have a good changelog comment with the patch so people
> > > > > > know what it is when they look in the logs?
> > > > > >
> > > > > > Care to resend it with that?
> > > > > >
> > > > >
> > > > > Base infrastructure to enable per-module debug messages.
> > > >
> > > > Ah, so close...
> > > >
> > > > With this patch, I get the following build error:
> > > >
> > > > CC [M] drivers/usb/gadget/u_ether.o
> > > > drivers/usb/gadget/u_ether.c: In function ___gether_setup___:
> > > > drivers/usb/gadget/u_ether.c:787: error: ___KBUILD_MODNAME___ undeclared (first use in this function)
> > > > drivers/usb/gadget/u_ether.c:787: error: (Each undeclared identifier is reported only once
> > > > drivers/usb/gadget/u_ether.c:787: error: for each function it appears in.)
> > > > drivers/usb/gadget/u_ether.c:787: error: unknown field ___Usage___ specified in initializer
> > > > drivers/usb/gadget/u_ether.c:787: error: expected expression before ___.___ token
> > > > drivers/usb/gadget/u_ether.c:787: error: initializer element is not constant
> > > > drivers/usb/gadget/u_ether.c:787: error: (near initialization for ___descriptor.hash___)
> > > > drivers/usb/gadget/u_ether.c:787: error: ___Usage___ undeclared (first use in this function)
> > > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ___long long int___ and ___char *___)
> > > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ___long long int___ and ___char *___)
> > > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ___long long int___ and ___char *___)
> > > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ___long long int___ and ___char *___)
> > > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > > > drivers/usb/gadget/u_ether.c:787: warning: passing argument 4 of _____dynamic_dbg_enabled_helper___ makes integer from pointer without a cast
> > > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___KBUILD_MODNAME___
> > >
> > > (lol at gcc crap)
> > >
> > > > drivers/usb/gadget/u_ether.c:787: warning: too few arguments for format
> > >
> > > argh, not that again. We had this with a patch from Jesse a while
> > > back, which I fixed thusly:
> >
> > <patch moving KBUILD_MODNAME from a inline function to a macro snipped>
> >
> > Yeah, I remember that too, but in this case, KBUILD_MODNAME is being
> > used in a macro, not an inline function, the exact opposite.
> >
> > Sam, any ideas here? I'll bounce the original patch at you if you
> > missed it last time.
>
> I have not looked into the particular error but what happens is
> that u_ether.o is used by more than one module so kbuild does
> not know what value to assign the KBUILD_MODNAME and therefore
> decide not to assign KBUILD_MODNAME at all.
>
> And because any usage of KBUILD_MODNAME is anyway flawed in u_ether.c
> as we do not know for what module it is being used it makes sense for
> kbuild to do so.
>
> The above error happens because u_ether.c uses something that require KBUILD_MODNAME
> to be define.
> So the correct fix is to avid usage of this macro in the source.
>
> Note: The old error Andrew mentions was caused by alpha indirectly
> pulling in a inline function that used KBUILD_MODNAME - something
> that did not happen on the other architectures.
>
> Sam
the comment above KBUILD_MODNAME from scripts/Makefile.lib says:
# Note: It's possible that one object gets potentially linked into more
# than one module. In that case KBUILD_MODNAME will be set to
# foo_bar,
# where foo and bar are the name of the modules.
That seems like a reasonable behavior to me...but that is not what the
code is doing...so at the very least the comment is wrong.
thanks,
-Jason
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-13 20:00 ` Sam Ravnborg
2008-08-13 22:49 ` jbaron
@ 2008-08-13 23:54 ` Greg KH
2008-08-14 1:25 ` Greg KH
1 sibling, 1 reply; 29+ messages in thread
From: Greg KH @ 2008-08-13 23:54 UTC (permalink / raw)
To: Sam Ravnborg; +Cc: Andrew Morton, jbaron, randy.dunlap, linux-kernel, joe, nick
On Wed, Aug 13, 2008 at 10:00:47PM +0200, Sam Ravnborg wrote:
> On Tue, Aug 12, 2008 at 08:38:59PM -0700, Greg KH wrote:
> > On Tue, Aug 12, 2008 at 06:16:53PM -0700, Andrew Morton wrote:
> > > On Tue, 12 Aug 2008 18:08:04 -0700
> > > Greg KH <greg@kroah.com> wrote:
> > >
> > > > On Tue, Aug 12, 2008 at 04:46:19PM -0400, Jason Baron wrote:
> > > > > On Tue, Aug 12, 2008 at 01:09:08PM -0700, Greg KH wrote:
> > > > > > So close, can I have a good changelog comment with the patch so people
> > > > > > know what it is when they look in the logs?
> > > > > >
> > > > > > Care to resend it with that?
> > > > > >
> > > > >
> > > > > Base infrastructure to enable per-module debug messages.
> > > >
> > > > Ah, so close...
> > > >
> > > > With this patch, I get the following build error:
> > > >
> > > > CC [M] drivers/usb/gadget/u_ether.o
> > > > drivers/usb/gadget/u_ether.c: In function ___gether_setup___:
> > > > drivers/usb/gadget/u_ether.c:787: error: ___KBUILD_MODNAME___ undeclared (first use in this function)
> > > > drivers/usb/gadget/u_ether.c:787: error: (Each undeclared identifier is reported only once
> > > > drivers/usb/gadget/u_ether.c:787: error: for each function it appears in.)
> > > > drivers/usb/gadget/u_ether.c:787: error: unknown field ___Usage___ specified in initializer
> > > > drivers/usb/gadget/u_ether.c:787: error: expected expression before ___.___ token
> > > > drivers/usb/gadget/u_ether.c:787: error: initializer element is not constant
> > > > drivers/usb/gadget/u_ether.c:787: error: (near initialization for ___descriptor.hash___)
> > > > drivers/usb/gadget/u_ether.c:787: error: ___Usage___ undeclared (first use in this function)
> > > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ___long long int___ and ___char *___)
> > > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ___long long int___ and ___char *___)
> > > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ___long long int___ and ___char *___)
> > > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ___long long int___ and ___char *___)
> > > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > > > drivers/usb/gadget/u_ether.c:787: warning: passing argument 4 of _____dynamic_dbg_enabled_helper___ makes integer from pointer without a cast
> > > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___KBUILD_MODNAME___
> > >
> > > (lol at gcc crap)
> > >
> > > > drivers/usb/gadget/u_ether.c:787: warning: too few arguments for format
> > >
> > > argh, not that again. We had this with a patch from Jesse a while
> > > back, which I fixed thusly:
> >
> > <patch moving KBUILD_MODNAME from a inline function to a macro snipped>
> >
> > Yeah, I remember that too, but in this case, KBUILD_MODNAME is being
> > used in a macro, not an inline function, the exact opposite.
> >
> > Sam, any ideas here? I'll bounce the original patch at you if you
> > missed it last time.
>
> I have not looked into the particular error but what happens is
> that u_ether.o is used by more than one module so kbuild does
> not know what value to assign the KBUILD_MODNAME and therefore
> decide not to assign KBUILD_MODNAME at all.
Ick.
Hm, how do I fix this? Build u_ether.c into two different .o files,
depending on which module it is being included into?
Or do:
#include "u_ether.c"
in the source code that was linking it in?
Actually, as ugly as that last one is, it probably would solve this
issue, and be the same end-result, right?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-13 23:54 ` Greg KH
@ 2008-08-14 1:25 ` Greg KH
0 siblings, 0 replies; 29+ messages in thread
From: Greg KH @ 2008-08-14 1:25 UTC (permalink / raw)
To: Sam Ravnborg; +Cc: Andrew Morton, jbaron, randy.dunlap, linux-kernel, joe, nick
On Wed, Aug 13, 2008 at 04:54:25PM -0700, Greg KH wrote:
> On Wed, Aug 13, 2008 at 10:00:47PM +0200, Sam Ravnborg wrote:
> > On Tue, Aug 12, 2008 at 08:38:59PM -0700, Greg KH wrote:
> > > On Tue, Aug 12, 2008 at 06:16:53PM -0700, Andrew Morton wrote:
> > > > On Tue, 12 Aug 2008 18:08:04 -0700
> > > > Greg KH <greg@kroah.com> wrote:
> > > >
> > > > > On Tue, Aug 12, 2008 at 04:46:19PM -0400, Jason Baron wrote:
> > > > > > On Tue, Aug 12, 2008 at 01:09:08PM -0700, Greg KH wrote:
> > > > > > > So close, can I have a good changelog comment with the patch so people
> > > > > > > know what it is when they look in the logs?
> > > > > > >
> > > > > > > Care to resend it with that?
> > > > > > >
> > > > > >
> > > > > > Base infrastructure to enable per-module debug messages.
> > > > >
> > > > > Ah, so close...
> > > > >
> > > > > With this patch, I get the following build error:
> > > > >
> > > > > CC [M] drivers/usb/gadget/u_ether.o
> > > > > drivers/usb/gadget/u_ether.c: In function ___gether_setup___:
> > > > > drivers/usb/gadget/u_ether.c:787: error: ___KBUILD_MODNAME___ undeclared (first use in this function)
> > > > > drivers/usb/gadget/u_ether.c:787: error: (Each undeclared identifier is reported only once
> > > > > drivers/usb/gadget/u_ether.c:787: error: for each function it appears in.)
> > > > > drivers/usb/gadget/u_ether.c:787: error: unknown field ___Usage___ specified in initializer
> > > > > drivers/usb/gadget/u_ether.c:787: error: expected expression before ___.___ token
> > > > > drivers/usb/gadget/u_ether.c:787: error: initializer element is not constant
> > > > > drivers/usb/gadget/u_ether.c:787: error: (near initialization for ___descriptor.hash___)
> > > > > drivers/usb/gadget/u_ether.c:787: error: ___Usage___ undeclared (first use in this function)
> > > > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ___long long int___ and ___char *___)
> > > > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > > > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ___long long int___ and ___char *___)
> > > > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary << (have ___long long int___ and ___char *___)
> > > > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > > > > drivers/usb/gadget/u_ether.c:787: error: invalid operands to binary & (have ___long long int___ and ___char *___)
> > > > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___:___ token
> > > > > drivers/usb/gadget/u_ether.c:787: warning: passing argument 4 of _____dynamic_dbg_enabled_helper___ makes integer from pointer without a cast
> > > > > drivers/usb/gadget/u_ether.c:787: error: expected ___)___ before ___KBUILD_MODNAME___
> > > >
> > > > (lol at gcc crap)
> > > >
> > > > > drivers/usb/gadget/u_ether.c:787: warning: too few arguments for format
> > > >
> > > > argh, not that again. We had this with a patch from Jesse a while
> > > > back, which I fixed thusly:
> > >
> > > <patch moving KBUILD_MODNAME from a inline function to a macro snipped>
> > >
> > > Yeah, I remember that too, but in this case, KBUILD_MODNAME is being
> > > used in a macro, not an inline function, the exact opposite.
> > >
> > > Sam, any ideas here? I'll bounce the original patch at you if you
> > > missed it last time.
> >
> > I have not looked into the particular error but what happens is
> > that u_ether.o is used by more than one module so kbuild does
> > not know what value to assign the KBUILD_MODNAME and therefore
> > decide not to assign KBUILD_MODNAME at all.
>
> Ick.
>
> Hm, how do I fix this? Build u_ether.c into two different .o files,
> depending on which module it is being included into?
>
> Or do:
> #include "u_ether.c"
> in the source code that was linking it in?
>
> Actually, as ugly as that last one is, it probably would solve this
> issue, and be the same end-result, right?
Argh, that code is just horrible!!!
I'll go split this up into separate sub-modules, like it really needs to
be. That will solve this problem.
Bah, why do people make things so hard...
thanks,
greg k-h
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-12 20:46 ` Jason Baron
2008-08-13 1:08 ` Greg KH
@ 2008-08-14 14:53 ` Greg KH
2008-08-14 21:05 ` Jason Baron
1 sibling, 1 reply; 29+ messages in thread
From: Greg KH @ 2008-08-14 14:53 UTC (permalink / raw)
To: Jason Baron; +Cc: Randy Dunlap, linux-kernel, akpm, joe, nick
On Tue, Aug 12, 2008 at 04:46:19PM -0400, Jason Baron wrote:
> On Tue, Aug 12, 2008 at 01:09:08PM -0700, Greg KH wrote:
> > So close, can I have a good changelog comment with the patch so people
> > know what it is when they look in the logs?
> >
> > Care to resend it with that?
> >
>
> Base infrastructure to enable per-module debug messages.
<snip>
Ok, I got the build problem with the usb-gadget drivers all worked out
now, and added this to my driver-core tree.
Very nice stuff, again, thanks for doing this. I'll work to clean up
the USB drivers to all rely on this and not their separate
CONFIG_USB_DEBUG option.
Also, would it make sense to add a patch like the one below to this
code? It might be nice to know when each module's debugging value is
manually changed by the user for the log files.
If you like it, I can merge it in the main patch.
thanks,
greg k-h
---
lib/dynamic_printk.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/lib/dynamic_printk.c
+++ b/lib/dynamic_printk.c
@@ -288,6 +288,9 @@ static ssize_t pr_debug_write(struct fil
num_enabled++;
dynamic_enabled = DYNAMIC_ENABLED_SOME;
err = 0;
+ printk(KERN_DEBUG
+ "debugging enabled for module %s",
+ elem->name);
} else if (!value && (elem->enable == 1)) {
elem->enable = 0;
num_enabled--;
@@ -304,6 +307,9 @@ static ssize_t pr_debug_write(struct fil
dynamic_enabled =
DYNAMIC_ENABLED_NONE;
err = 0;
+ printk(KERN_DEBUG
+ "debugging disabled for module "
+ "%s", elem->name);
}
}
}
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-08-14 14:53 ` Greg KH
@ 2008-08-14 21:05 ` Jason Baron
0 siblings, 0 replies; 29+ messages in thread
From: Jason Baron @ 2008-08-14 21:05 UTC (permalink / raw)
To: Greg KH; +Cc: Randy Dunlap, linux-kernel, akpm, joe, nick
On Thu, Aug 14, 2008 at 07:53:48AM -0700, Greg KH wrote:
> Also, would it make sense to add a patch like the one below to this
> code? It might be nice to know when each module's debugging value is
> manually changed by the user for the log files.
>
> If you like it, I can merge it in the main patch.
>
> thanks,
>
> greg k-h
>
> ---
> lib/dynamic_printk.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> --- a/lib/dynamic_printk.c
> +++ b/lib/dynamic_printk.c
> @@ -288,6 +288,9 @@ static ssize_t pr_debug_write(struct fil
> num_enabled++;
> dynamic_enabled = DYNAMIC_ENABLED_SOME;
> err = 0;
> + printk(KERN_DEBUG
> + "debugging enabled for module %s",
> + elem->name);
> } else if (!value && (elem->enable == 1)) {
> elem->enable = 0;
> num_enabled--;
> @@ -304,6 +307,9 @@ static ssize_t pr_debug_write(struct fil
> dynamic_enabled =
> DYNAMIC_ENABLED_NONE;
> err = 0;
> + printk(KERN_DEBUG
> + "debugging disabled for module "
> + "%s", elem->name);
> }
> }
> }
looks good. we might also want to add a message for the cases where are the
modules are enabled/disabled too.
thanks,
-Jason
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] dynamic debug v2 - infrastructure
2008-07-15 21:31 [PATCH 1/7] dynamic debug v2 - infrastructure Jason Baron
2008-07-17 7:01 ` Greg KH
@ 2008-09-16 0:03 ` Rusty Russell
1 sibling, 0 replies; 29+ messages in thread
From: Rusty Russell @ 2008-09-16 0:03 UTC (permalink / raw)
To: Jason Baron; +Cc: linux-kernel, akpm, joe, greg, nick, randy.dunlap
On Wednesday 16 July 2008 07:31:08 Jason Baron wrote:
> --- a/include/linux/module.h
> +++ b/include/linux/module.h
> @@ -359,6 +359,10 @@ struct module
> struct marker *markers;
> unsigned int num_markers;
> #endif
> +#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
> + struct mod_debug *start_verbose;
> + unsigned int num_verbose;
> +#endif
Hi Jason,
Couple of nit-picks about the module part of this patch. First, this could
just be called "verbose" rather than "start_verbose"...
> @@ -1717,6 +1718,9 @@ static struct module *load_module(void __user *umod,
> unsigned int unusedgplcrcindex;
> unsigned int markersindex;
> unsigned int markersstringsindex;
> + unsigned int verboseindex;
> + struct mod_debug *iter;
> + unsigned long value;
> struct module *mod;
> long err = 0;
> void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
> @@ -1993,6 +1997,7 @@ static struct module *load_module(void __user *umod,
> markersindex = find_sec(hdr, sechdrs, secstrings, "__markers");
> markersstringsindex = find_sec(hdr, sechdrs, secstrings,
> "__markers_strings");
> + verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose");
>
> /* Now do relocations. */
> for (i = 1; i < hdr->e_shnum; i++) {
> @@ -2020,6 +2025,11 @@ static struct module *load_module(void __user *umod,
> mod->num_markers =
> sechdrs[markersindex].sh_size / sizeof(*mod->markers);
> #endif
> +#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
> + mod->start_verbose = (void *)sechdrs[verboseindex].sh_addr;
> + mod->num_verbose = sechdrs[verboseindex].sh_size /
> + sizeof(*mod->start_verbose);
> +#endif
>
> /* Find duplicate symbols */
> err = verify_export_symbols(mod);
> @@ -2043,6 +2053,19 @@ static struct module *load_module(void __user *umod,
> marker_update_probe_range(mod->markers,
> mod->markers + mod->num_markers);
> #endif
> +#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
> + for (value = (unsigned long)mod->start_verbose;
> + value < (unsigned long)mod->start_verbose +
> + (unsigned long)(mod->num_verbose * sizeof(struct mod_debug));
> + value += sizeof(struct mod_debug)) {
> + iter = (struct mod_debug *)value;
> + register_debug_module(iter->modname,
> + simple_strtoul(iter->type, NULL, 10),
> + iter->logical_modname,
> + simple_strtoul(iter->num_flags, NULL, 10),
> + iter->flag_names);
> + }
> +#endif
This loop seems way more complex than it needs to be. Perhaps pull these two
out into a setup_verbose_debug() func which is a noop
for !CONFIG_DYNAMIC_PRINTK_DEBUG, and drop all the casts?
Thanks,
Rusty.
^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2008-09-16 0:03 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-15 21:31 [PATCH 1/7] dynamic debug v2 - infrastructure Jason Baron
2008-07-17 7:01 ` Greg KH
2008-07-17 21:20 ` Jason Baron
2008-07-17 22:32 ` Greg KH
2008-07-17 22:56 ` Dominik Brodowski
2008-07-17 23:35 ` Greg KH
2008-07-18 6:37 ` Dominik Brodowski
2008-07-18 14:39 ` Jason Baron
2008-08-08 21:51 ` Jason Baron
2008-08-09 1:07 ` Greg KH
2008-08-11 14:12 ` Jason Baron
2008-08-11 16:45 ` Greg KH
2008-08-09 2:38 ` Randy Dunlap
2008-08-11 17:36 ` Jason Baron
2008-08-11 22:33 ` Greg KH
2008-08-12 19:48 ` Jason Baron
2008-08-12 20:09 ` Greg KH
2008-08-12 20:46 ` Jason Baron
2008-08-13 1:08 ` Greg KH
2008-08-13 1:16 ` Andrew Morton
2008-08-13 3:38 ` Greg KH
2008-08-13 20:00 ` Sam Ravnborg
2008-08-13 22:49 ` jbaron
2008-08-13 23:54 ` Greg KH
2008-08-14 1:25 ` Greg KH
2008-08-13 19:05 ` Jason Baron
2008-08-14 14:53 ` Greg KH
2008-08-14 21:05 ` Jason Baron
2008-09-16 0:03 ` Rusty Russell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox