Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 346e15be authored by Jason Baron's avatar Jason Baron Committed by Greg Kroah-Hartman
Browse files

driver core: basic infrastructure for per-module dynamic debug messages



Base infrastructure to enable per-module debug messages.

I've introduced CONFIG_DYNAMIC_PRINTK_DEBUG, which when enabled centralizes
control of debugging statements on a per-module basis in one /proc file,
currently, <debugfs>/dynamic_printk/modules. When, CONFIG_DYNAMIC_PRINTK_DEBUG,
is not set, debugging statements can still be enabled as before, often by
defining 'DEBUG' for the proper compilation unit. Thus, this patch set has no
affect when CONFIG_DYNAMIC_PRINTK_DEBUG is not set.

The infrastructure currently ties into all pr_debug() and dev_dbg() calls. That
is, if CONFIG_DYNAMIC_PRINTK_DEBUG is set, all pr_debug() and dev_dbg() calls
can be dynamically enabled/disabled on a per-module basis.

Future plans include extending this functionality to subsystems, that define 
their own debug levels and flags.

Usage:

Dynamic debugging is controlled by the debugfs file, 
<debugfs>/dynamic_printk/modules. This file contains a list of the modules that
can be enabled. The format of the file is as follows:

	<module_name> <enabled=0/1>
		.
		.
		.

	<module_name> : Name of the module in which the debug call resides
	<enabled=0/1> : whether the messages are enabled or not

For example:

	snd_hda_intel enabled=0
	fixup enabled=1
	driver enabled=0

Enable a module:

	$echo "set enabled=1 <module_name>" > dynamic_printk/modules

Disable a module:

	$echo "set enabled=0 <module_name>" > dynamic_printk/modules

Enable all modules:

	$echo "set enabled=1 all" > dynamic_printk/modules

Disable all modules:

	$echo "set enabled=0 all" > dynamic_printk/modules

Finally, passing "dynamic_printk" at the command line enables
debugging for all modules. This mode can be turned off via the above
disable command.

[gkh: minor cleanups and tweaks to make the build work quietly]

Signed-off-by: default avatarJason Baron <jbaron@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 33376c1c
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -1713,6 +1713,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
+9 −1
Original line number Diff line number Diff line
@@ -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)							\
+5 −1
Original line number Diff line number Diff line
@@ -550,7 +550,11 @@ extern const char *dev_driver_string(const 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
+93 −0
Original line number Diff line number Diff line
#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
+6 −1
Original line number Diff line number Diff line
@@ -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 *buf, u8 byte)
#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
Loading