From: Jason Baron <jbaron@redhat.com>
To: Greg KH <greg@kroah.com>
Cc: linux-kernel@vger.kernel.org, akpm@linux-foundation.org,
joe@perches.com, nick@nick-andrew.net, randy.dunlap@oracle.com
Subject: Re: [PATCH 1/7] dynamic debug v2 - infrastructure
Date: Fri, 8 Aug 2008 17:51:53 -0400 [thread overview]
Message-ID: <20080808215153.GA16729@redhat.com> (raw)
In-Reply-To: <20080717223222.GA28016@kroah.com>
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);
+}
+
next prev parent reply other threads:[~2008-08-08 21:53 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080808215153.GA16729@redhat.com \
--to=jbaron@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=greg@kroah.com \
--cc=joe@perches.com \
--cc=linux-kernel@vger.kernel.org \
--cc=nick@nick-andrew.net \
--cc=randy.dunlap@oracle.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.