--- /dev/null
+From jbaron@redhat.com Tue Aug 12 17:09:39 2008
+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>
+Patch-mainline: 2.6.28
+
+Base infrastructure to enable per-module debug messages.
+
+I've introduced CONFIG_DYNAMIC_PRINTK_DEBUG, which when enabled centralizes
+control of debugging statements on a per-module basis in one /proc file,
+currently, <debugfs>/dynamic_printk/modules. When, CONFIG_DYNAMIC_PRINTK_DEBUG,
+is not set, debugging statements can still be enabled as before, often by
+defining 'DEBUG' for the proper compilation unit. Thus, this patch set has no
+affect when CONFIG_DYNAMIC_PRINTK_DEBUG is not set.
+
+The infrastructure currently ties into all pr_debug() and dev_dbg() calls. That
+is, if CONFIG_DYNAMIC_PRINTK_DEBUG is set, all pr_debug() and dev_dbg() calls
+can be dynamically enabled/disabled on a per-module basis.
+
+Future plans include extending this functionality to subsystems, that define
+their own debug levels and flags.
+
+Usage:
+
+Dynamic debugging is controlled by the debugfs file,
+<debugfs>/dynamic_printk/modules. This file contains a list of the modules that
+can be enabled. The format of the file is as follows:
+
+ <module_name> <enabled=0/1>
+ .
+ .
+ .
+
+ <module_name> : Name of the module in which the debug call resides
+ <enabled=0/1> : whether the messages are enabled or not
+
+For example:
+
+ snd_hda_intel enabled=0
+ fixup enabled=1
+ driver enabled=0
+
+Enable a module:
+
+ $echo "set enabled=1 <module_name>" > dynamic_printk/modules
+
+Disable a module:
+
+ $echo "set enabled=0 <module_name>" > dynamic_printk/modules
+
+Enable all modules:
+
+ $echo "set enabled=1 all" > dynamic_printk/modules
+
+Disable all modules:
+
+ $echo "set enabled=0 all" > dynamic_printk/modules
+
+Finally, passing "dynamic_printk" at the command line enables
+debugging for all modules. This mode can be turned off via the above
+disable command.
+
+[gkh: minor cleanups and tweaks to make the build work quietly]
+
+Signed-off-by: Jason Baron <jbaron@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ Documentation/kernel-parameters.txt | 5
+ include/asm-generic/vmlinux.lds.h | 10
+ include/linux/device.h | 6
+ include/linux/dynamic_printk.h | 93 ++++++++
+ include/linux/kernel.h | 7
+ include/linux/module.h | 1
+ kernel/module.c | 31 ++
+ lib/Kconfig.debug | 55 ++++
+ lib/Makefile | 2
+ lib/dynamic_printk.c | 418 ++++++++++++++++++++++++++++++++++++
+ net/netfilter/nf_conntrack_pptp.c | 2
+ scripts/Makefile.lib | 11
+ scripts/basic/Makefile | 2
+ scripts/basic/hash.c | 64 +++++
+ 14 files changed, 700 insertions(+), 7 deletions(-)
+
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -1735,6 +1735,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
+@@ -553,7 +553,11 @@ int printk_dev_hash(const char *, const
+ #define dev_info(dev, format, arg...) \
+ dev_printk_hash(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,93 @@
++#ifndef _DYNAMIC_PRINTK_H
++#define _DYNAMIC_PRINTK_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>
+
+@@ -331,8 +332,12 @@ int printk_hash(const char *, const char
+ #define pr_info(fmt, arg...) \
+ pr_printk_hash(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...) \
+ pr_printk(KERN_DEBUG, fmt, ##arg)
+ #else
+--- a/include/linux/module.h
++++ b/include/linux/module.h
+@@ -345,7 +345,6 @@ struct module
+ /* Reference counts */
+ struct module_ref ref[NR_CPUS];
+ #endif
+-
+ };
+ #ifndef MODULE_ARCH_INIT
+ #define MODULE_ARCH_INIT {}
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -798,6 +798,7 @@ SYSCALL_DEFINE2(delete_module, const cha
+ 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:
+@@ -1823,6 +1824,33 @@ static inline void add_kallsyms(struct m
+ }
+ #endif /* CONFIG_KALLSYMS */
+
++#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
++static void dynamic_printk_setup(Elf_Shdr *sechdrs, unsigned int verboseindex)
++{
++ struct mod_debug *debug_info;
++ unsigned long pos, end;
++ unsigned int num_verbose;
++
++ pos = sechdrs[verboseindex].sh_addr;
++ num_verbose = sechdrs[verboseindex].sh_size /
++ sizeof(struct mod_debug);
++ end = pos + (num_verbose * sizeof(struct mod_debug));
++
++ for (; pos < end; pos += sizeof(struct mod_debug)) {
++ debug_info = (struct mod_debug *)pos;
++ register_dynamic_debug_module(debug_info->modname,
++ debug_info->type, debug_info->logical_modname,
++ debug_info->flag_names, debug_info->hash,
++ debug_info->hash2);
++ }
++}
++#else
++static inline void dynamic_printk_setup(Elf_Shdr *sechdrs,
++ unsigned int verboseindex)
++{
++}
++#endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */
++
+ static void *module_alloc_update_bounds(unsigned long size)
+ {
+ void *ret = module_alloc(size);
+@@ -1871,6 +1899,7 @@ static noinline struct module *load_modu
+ #endif
+ unsigned int markersindex;
+ unsigned int markersstringsindex;
++ unsigned int verboseindex;
+ struct module *mod;
+ long err = 0;
+ void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
+@@ -2157,6 +2186,7 @@ static noinline struct module *load_modu
+ 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++) {
+@@ -2207,6 +2237,7 @@ static noinline struct module *load_modu
+ marker_update_probe_range(mod->markers,
+ mod->markers + mod->num_markers);
+ #endif
++ dynamic_printk_setup(sechdrs, verboseindex);
+ err = module_finalize(hdr, sechdrs, mod);
+ if (err < 0)
+ goto cleanup;
+--- /dev/null
++++ b/lib/dynamic_printk.c
+@@ -0,0 +1,418 @@
++/*
++ * 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;
++ printk(KERN_DEBUG
++ "debugging enabled for module %s",
++ elem->name);
++ } 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;
++ printk(KERN_DEBUG
++ "debugging disabled for module "
++ "%s", elem->name);
++ }
++ }
++ }
++ }
++ 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
+@@ -752,6 +752,61 @@ menuconfig BUILD_DOCSRC
+
+ Say N if you are unsure.
+
++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
+@@ -81,6 +81,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)