]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.drivers/driver-core-basic-infrastructure-for-per-module-dynamic-debug-messages.patch
Move xen patchset to new version's subdir.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.drivers / driver-core-basic-infrastructure-for-per-module-dynamic-debug-messages.patch
diff --git a/src/patches/suse-2.6.27.31/patches.drivers/driver-core-basic-infrastructure-for-per-module-dynamic-debug-messages.patch b/src/patches/suse-2.6.27.31/patches.drivers/driver-core-basic-infrastructure-for-per-module-dynamic-debug-messages.patch
new file mode 100644 (file)
index 0000000..cbc48b2
--- /dev/null
@@ -0,0 +1,946 @@
+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)