debug printk infrastructure -base patch
PATCH 1/8 debug printk infrastructure -base patch
--- include/asm-generic/vmlinux.lds.h | 14 ++- include/linux/device.h | 16 ++ include/linux/dynamic_printk.h | 44 +++++ include/linux/kernel.h | 16 ++ include/linux/module.h | 5 + kernel/module.c | 20 +++ lib/Kconfig.debug | 46 +++++ lib/Makefile | 2 + lib/dynamic_printk.c | 327 +++++++++++++++++++++++++++++++++++++ 9 files changed, 489 insertions(+), 1 deletions(-) create mode 100644 include/linux/dynamic_printk.h create mode 100644 lib/dynamic_printk.c
include/asm-generic/vmlinux.lds.h +12 -0
@@ -168,6 +168,18 @@ *(__ksymtab_strings) \ } \ \ +/* dynamic printk sections: strings */ \ + __verbose_strings : AT(ADDR(__verbose_strings) - LOAD_OFFSET) { \ + *(__verbose_strings) \ + } \ + \ +/* dynamic printk sections: strings */ \ + __verbose : AT(ADDR(__verbose) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___verbose) = .; \ + *(__verbose ) \ + VMLINUX_SYMBOL(__stop___verbose) = .; \ + } \ + \/* __*init sections */ \ __init_rodata : AT(ADDR(__init_rodata) - LOAD_OFFSET) { \ *(.ref.rodata) \
include/linux/device.h +16 -0
@@ -595,6 +595,22 @@ extern const char *dev_driver_string(struct device *dev);#ifdef DEBUG #define dev_dbg(dev, format, arg...) \ dev_printk(KERN_DEBUG , dev , format , ## arg) +#elif defined(CONFIG_DYNAMIC_PRINTK_DEBUG ) +#define dev_dbg (dev, format, ...) do { \ + static char bar[] \ + __attribute__((section("__verbose_strings"))) \ + = KBUILD_MODNAME; \ + static struct mod_debug foobar \ + __used \ + __attribute__((section("__verbose"), unused)) = \ + { bar }; \ + int hash = dynamic_name_hash(KBUILD_MODNAME); \ + if (dynamic_printk_enabled[smp_processor_id()] & (1 << hash)) \ + dynamic_printk(KBUILD_MODNAME, \ + KERN_DEBUG KBUILD_MODNAME ": %s %s: " format,\ + dev_driver_string(dev), (dev)->bus_id, \ + ##__VA_ARGS__); \ + } while (0)#else #define dev_dbg(dev, format, arg...) \ ({ if (0) dev_printk(KERN_DEBUG, dev, format, ##arg); 0; })
include/linux/dynamic_printk.h new file +44 -0
44 lines not on this page · raw message
include/linux/kernel.h +16 -0
@@ -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>
@@ -292,6 +293,21 @@ extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type,/* If you are writing a driver, please use dev_dbg instead */ #define pr_debug(fmt, arg...) \ printk(KERN_DEBUG fmt, ##arg) +#elif defined(CONFIG_DYNAMIC_PRINTK_DEBUG ) +#define pr_debug (fmt, ...) do { \ + static char bar[] \ + __attribute__((section("__verbose_strings"))) \ + = KBUILD_MODNAME; \ + static struct mod_debug foobar \ + __used \ + __attribute__((section("__verbose"), unused)) = \ + { bar }; \ + int hash = dynamic_name_hash(KBUILD_MODNAME); \ + if (dynamic_printk_enabled[smp_processor_id()] & (1 << hash)) \ + dynamic_printk(KBUILD_MODNAME, \ + KERN_DEBUG KBUILD_MODNAME ": " fmt,\ + ##__VA_ARGS__); \ + } while (0)#else #define pr_debug(fmt, arg...) \ ({ if (0) printk(KERN_DEBUG fmt, ##arg); 0; })
include/linux/module.h +5 -0
@@ -16,6 +16,7 @@#include <linux/kobject.h> #include <linux/moduleparam.h> #include <linux/marker.h> +#include <linux/dynamic_printk.h> #include <asm/local.h> #include <asm/module.h>
@@ -359,6 +360,10 @@ struct modulestruct marker *markers;unsigned int num_markers;#endif +#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG +struct mod_debug *verbose; +unsigned int num_verbose; +#endif };#ifndef MODULE_ARCH_INIT #define MODULE_ARCH_INIT {}
kernel/module.c +20 -0
@@ -42,6 +42,7 @@#include <linux/string.h> #include <linux/mutex.h> #include <linux/unwind.h> +#include <linux/dynamic_printk.h> #include <asm/uaccess.h> #include <asm/cacheflush.h> #include <linux/license.h>
@@ -744,6 +745,9 @@ 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)); +#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG +remove_module (mod->name); +#endif free_module (mod); out:
@@ -1717,6 +1721,9 @@ static struct module *load_module(void __user *umod,unsigned int unusedgplcrcindex;unsigned int markersindex;unsigned int markersstringsindex; +unsigned int verboseindex; +unsigned int verbosestringsindex; +struct mod_debug *iter;struct module *mod;long err =0 ;void *percpu =NULL , *ptr =NULL ;/* Stops spurious gcc warning */
@@ -1993,6 +2000,9 @@ 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" ); + verbosestringsindex =find_sec (hdr, sechdrs, secstrings, +"__verbose_strings" );/* Now do relocations. */ for (i =1 ; i < hdr->e_shnum; i++) {
@@ -2020,6 +2030,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->verbose = (void *)sechdrs[verboseindex].sh_addr; + mod->num_verbose = + sechdrs[verboseindex].sh_size /sizeof (*mod->verbose); +#endif /* Find duplicate symbols */ err =verify_export_symbols (mod);
@@ -2043,6 +2058,11 @@ 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 (iter = mod->verbose; iter < mod->verbose+mod->num_verbose; iter++) { +add_module (iter->modname); + } +#endif err =module_finalize (hdr, sechdrs, mod);if (err <0 ) goto cleanup;
lib/Kconfig.debug +46 -0
52 lines not on this page · raw message
lib/Makefile +2 -0
@@ -66,6 +66,8 @@ obj-$(CONFIG_SWIOTLB) += swiotlb.o obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o +obj-$(CONFIG_PRINTK_DEBUG) += dynamic_printk.o + lib-$(CONFIG_GENERIC_BUG) += bug.o obj-$(CONFIG_HAVE_LMB) += lmb.o
lib/dynamic_printk.c new file +327 -0
327 lines not on this page · raw message
Signature · 1 line
1.5.4.5
Andrew Morton
maintainerQuoted 2 lines · On Thu, 22 May 2008 17:14:53 -0400 Jason Baron <[email protected]> wrote:
Signed-off-by Jason Baron <[email protected]>
-ENOCHANGELOG :(
Quoted 27 lines
--- include/asm-generic/vmlinux.lds.h | 14 ++- include/linux/device.h | 16 ++ include/linux/dynamic_printk.h | 44 +++++ include/linux/kernel.h | 16 ++ include/linux/module.h | 5 + kernel/module.c | 20 +++ lib/Kconfig.debug | 46 +++++ lib/Makefile | 2 + lib/dynamic_printk.c | 327 +++++++++++++++++++++++++++++++++++++ 9 files changed, 489 insertions(+), 1 deletions(-) create mode 100644 include/linux/dynamic_printk.h create mode 100644 lib/dynamic_printk.cinclude/asm-generic/vmlinux.lds.h +5
-0@@ -168,6 +168,18 @@ *(__ksymtab_strings) \ } \ \ +/* dynamic printk sections: strings */ \ + __verbose_strings : AT(ADDR(__verbose_strings) - LOAD_OFFSET) { \ + *(__verbose_strings) \ + } \ + \
include/asm-generic/vmlinux.lds.h line 185
Quoted 10 lines
include/asm-generic/vmlinux.lds.h +7
-0+/* dynamic printk sections: strings */ \ + __verbose : AT(ADDR(__verbose) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___verbose) = .; \ + *(__verbose ) \ + VMLINUX_SYMBOL(__stop___verbose) = .; \ + } \ + \/* __*init sections */ \ __init_rodata : AT(ADDR(__init_rodata) - LOAD_OFFSET) { \ *(.ref.rodata) \
Please add code comments explaining what all this stuff is doing and why it exists, etc. Also a high-level overview in the changelog would be appropriate.
Quoted 14 lines
include/linux/device.h +6
-0@@ -595,6 +595,22 @@ extern const char *dev_driver_string(struct device *dev);#ifdef DEBUG #define dev_dbg(dev, format, arg...) \ dev_printk(KERN_DEBUG , dev , format , ## arg) +#elif defined(CONFIG_DYNAMIC_PRINTK_DEBUG ) +#define dev_dbg (dev, format, ...) do { \ + static char bar[] \ + __attribute__((section("__verbose_strings"))) \ + = KBUILD_MODNAME; \ + static struct mod_debug foobar \
include/linux/device.h extern const char *dev_driver_string(struct device *dev); · line 613
Quoted 10 lines
include/linux/device.h +10
-0+__used \ + __attribute__((section("__verbose"), unused)) = \ + { bar }; \ +int hash =dynamic_name_hash (KBUILD_MODNAME ); \ +if (dynamic_printk_enabled[smp_processor_id ()] & (1 << hash)) \ +dynamic_printk (KBUILD_MODNAME , \ + KERN_DEBUG KBUILD_MODNAME ": %s %s: " format,\ +dev_driver_string (dev), (dev)->bus_id, \ + ##__VA_ARGS__); \ + }while (0 )
Please choose communicative identifiers rather than foo, fiibar, etc.
If poss, please confirm that even old versions of gcc don't go an instantiate multiple versions of bar[] in a single compilation unit. That would be most sad.
The if' expression should have unlikely' wrapped around it?
That smp_processor_id() will surely trigger use-of-smp_processor_id-in-preemptible-code warnings? The useful but oft ignore Documentation/SubmitChecklist covers this.
It's weird to see "(1 << hash)", where afaict `hash' can have values in the 0->4G range. Won't this give zero most of the time?
Some code comments here whcih explain what is going on would be beneficial.
Quoted 43 lines
include/linux/device.h +0
-0#else #define dev_dbg(dev, format, arg...) \ ({ if (0) dev_printk(KERN_DEBUG, dev, format, ##arg); 0; })include/linux/dynamic_printk.h new file +34
-0@@ -0,0 +1,44 @@ +#ifndef _DYNAMIC_PRINTK_H +#define _DYNAMIC_PRINTK_H + +#ifdef __KERNEL__ + +#include <linux/string.h> + +#define DYNAMIC_HASH_BITS 5 +#define FILE_TABLE_SIZE (1 << DYNAMIC_HASH_BITS) + +struct mod_debug { + char *modname; +}; + +void add_module(char *); +int remove_module(char *); + +extern int dynamic_printk_enabled[]; +extern void dynamic_printk(char *, char *, ...); + +static inline unsigned long +dynamic_partial_name_hash(unsigned long c, unsigned long prevhash) +{ + return (prevhash + (c << 4) + (c >> 4)) * 11; +} + + +static inline unsigned int +dynamic_full_name_hash(const unsigned char *name, unsigned int len) +{ + unsigned long hash = 0; + while (len--) + hash = dynamic_partial_name_hash(*name++, hash); + return hash;
include/linux/dynamic_printk.h line 44
Quoted 10 lines
include/linux/dynamic_printk.h new file +10
-0+} + +static inline unsigned int dynamic_name_hash (char *name) +{ +unsigned int hash =dynamic_full_name_hash (name,strlen (name)); +return (hash & ((1 <<DYNAMIC_HASH_BITS ) -1 )); +} + +#endif +#endif
What's all this doing? Some general overall comments would help.
Did we really need to implement new hash functions for <whatever this is for>? Was it not possible to reuse some existing infrastructure?
This new code is quite generic-looking and uses generic identifiers. But it is inappropriately placed inside a file called "dynamic_printk.h".
If you have indeed identified a gap in core kernel infrastructure then can we please plug it appropriately? Implement the new hashing function as a standalone patch, put it into appropriately named .c and .h files and provide appropriate changelogging and comments? The idea being that dynamic printk is the first client of that new infrastructure, but we expect that there will be others users in the future. And perhaps some existing code which presently uses private implementations can be converted to use the new generic code.
The identifier FILE_TABLE_SIZE is too generic-sounding for something which is specific to the dynamic printk subsystem. For your internal identifiers I'd suggest that you pick a prefix string for this subsystem and stick to using it everywhere.
Similary DYNAMIC_HASH_BITS doesn't sound very appropriate.
Quoted 21 lines
include/linux/kernel.h +6
-0@@ -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> @@ -292,6 +293,21 @@ extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type,/* If you are writing a driver, please use dev_dbg instead */ #define pr_debug(fmt, arg...) \ printk(KERN_DEBUG fmt, ##arg) +#elif defined(CONFIG_DYNAMIC_PRINTK_DEBUG ) +#define pr_debug (fmt, ...) do { \ + static char bar[] \ + __attribute__((section("__verbose_strings"))) \ + = KBUILD_MODNAME; \
include/linux/kernel.h extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type, · line 310
Quoted 10 lines
include/linux/kernel.h +10
-0+ static struct mod_debug foobar \ +__used \ + __attribute__((section("__verbose"), unused)) = \ + { bar }; \ +int hash =dynamic_name_hash (KBUILD_MODNAME ); \ +if (dynamic_printk_enabled[smp_processor_id ()] & (1 << hash)) \ +dynamic_printk (KBUILD_MODNAME , \ + KERN_DEBUG KBUILD_MODNAME ": " fmt,\ + ##__VA_ARGS__); \ + }while (0 )
That's super-similar to the above dev_dbg(). Can they share code?
The above observations against dev_dbg() apply here.
The above hunk adds trailing whitespace. Please feed all patches through checkpatch to pick up things like this.
Quoted 39 lines
include/linux/kernel.h +0
-0#else #define pr_debug(fmt, arg...) \ ({ if (0) printk(KERN_DEBUG fmt, ##arg); 0; })include/linux/module.h +5
-0@@ -16,6 +16,7 @@#include <linux/kobject.h> #include <linux/moduleparam.h> #include <linux/marker.h> +#include <linux/dynamic_printk.h> #include <asm/local.h> #include <asm/module.h> @@ -359,6 +360,10 @@ struct modulestruct marker *markers;unsigned int num_markers;#endif +#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG +struct mod_debug *verbose; +unsigned int num_verbose; +#endif };#ifndef MODULE_ARCH_INIT #define MODULE_ARCH_INIT {}kernel/module.c +1
-0@@ -42,6 +42,7 @@#include <linux/string.h> #include <linux/mutex.h> #include <linux/unwind.h> +#include <linux/dynamic_printk.h> #include <asm/uaccess.h> #include <asm/cacheflush.h> #include <linux/license.h>
kernel/module.c sys_delete_module(const char __user *name_user, unsigned int flags) · line 751
Quoted 7 lines
kernel/module.c +3
-0@@ -744,6 +745,9 @@ 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)); +#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG +remove_module (mod->name); +#endif free_module (mod);
Adds trailing whitepace.
It would be preferable to add
#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
extern int remove_module(const char *modname); #else
static inline int remove_module(const char *modname)
{
return 0;
}#endif
to a header file, so we reduce the ifdef density. (Note the `cosnt char' too).
Is it correct to ignore the remove_module() return value here?
kernel/module.c static struct module *load_module(void __user *umod, · line 1725
Quoted 7 lines
kernel/module.c +2
-0out:@@ -1717,6 +1721,9 @@ static struct module *load_module(void __user *umod,unsigned int unusedgplcrcindex;unsigned int markersindex;unsigned int markersstringsindex; +unsigned int verboseindex; +unsigned int verbosestringsindex;
verbose_index and verbose_strings_index, please.
Quoted 15 lines
kernel/module.c +4
-0+struct mod_debug *iter;struct module *mod;long err =0 ;void *percpu =NULL , *ptr =NULL ;/* Stops spurious gcc warning */ @@ -1993,6 +2000,9 @@ 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" ); + verbosestringsindex =find_sec (hdr, sechdrs, secstrings, +"__verbose_strings" );/* Now do relocations. */ for (i =1 ; i < hdr->e_shnum; i++) {
kernel/module.c static struct module *load_module(void __user *umod, · line 2034
Quoted 5 lines
kernel/module.c +2
-0@@ -2020,6 +2030,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->verbose = (void *)sechdrs[verboseindex].sh_addr;
What is the cast for here?
Quoted 7 lines
kernel/module.c +3
-0+ mod->num_verbose = + sechdrs[verboseindex].sh_size /sizeof (*mod->verbose); +#endif /* Find duplicate symbols */ err =verify_export_symbols (mod);
kernel/module.c static struct module *load_module(void __user *umod, · line 2065
Quoted 8 lines
kernel/module.c +5
-0@@ -2043,6 +2058,11 @@ 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 (iter = mod->verbose; iter < mod->verbose+mod->num_verbose; iter++) { +add_module (iter->modname); + } +#endif
Unneeded braces.
Whitespace broke - please use hard tabs for indentation (this is me emulating checkpatch).
Quoted 46 lines
kernel/module.c +0
-0err =module_finalize (hdr, sechdrs, mod);if (err <0 ) goto cleanup;lib/Kconfig.debug +35
-0@@ -632,6 +632,52 @@ config FIREWIRE_OHCI_REMOTE_DMA If unsure, say N. +config PRINTK_DEBUG + bool "Enable centralized debug printk() call support" + default n + depends on PRINTK + +config DYNAMIC_PRINTK_DEBUG + bool "Enable dynamic printk() call support" + default n + depends on PRINTK + select PRINTK_DEBUG + help + + Allows pr_debug() and dev_dbg() calls to be dynamically enabled based + upon their source module. Traditionally, these calls are only + enabled if one set #define DEBUG and recompiled the kernel. This + option obviates time consuming re-compiles. + + The impact of this compile option is a larger kerenl text size ~1%. + However, if CONFIG_IMMEDIATE is set, the run-time impact is + negligible. Without CONFIG_IMMEDIATE set, a global variable is + referenced for each pr_debug() and dev_dbg() calls. + + Usage: + + The printing of pr_debug() and dev_dbg() is controlled by the + debugfs file, dynamic_printk/modules. This file contains a list of + the active modules. To add and remove modules: + + echo "add <module_name>" > dynamic_printk/modules + echo "remove <module_name>" > dynamic_printk/modules + + For example: + + echo "add kobject" > dynamic_printk/modules + /sbin/modprobe <module>
lib/Kconfig.debug config FIREWIRE_OHCI_REMOTE_DMA · line 679
Quoted 10 lines
lib/Kconfig.debug +10
-0+ + This will cause kobject debug messages to spew out. Also, a special + "all" value will print all pr_debug() and dev_dbg() calls. I.e.: + + echo "add all" > dynamic_printk/modules + echo "remove all" > dynamic_printk/modules + + Finally, passing "dynamic_printk" at the command line enables all + pr_debug() and dev_dbg() call to come out (same as "all"). This mode + can be disabled via a "remove all".
It discusses CONFIG_IMMEDIATE but I don't see what that is.
Quoted 18 lines
lib/dynamic_printk.c new file +15
-0@@ -0,0 +1,327 @@ +/* +* 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 <[email protected]> +*/ + +#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>
lib/dynamic_printk.c line 25
Quoted 10 lines
lib/dynamic_printk.c new file +10
-0+#include <linux/hash.h> +#include <linux/dynamic_printk.h> + +extern struct mod_debug __start___verbose[]; +extern struct mod_debug __stop___verbose[]; + +static int num_enabled; +static struct hlist_head module_table[FILE_TABLE_SIZE ] = + { [0 ...FILE_TABLE_SIZE -1 ] =HLIST_HEAD_INIT }; +static DECLARE_MUTEX (debug_list_mutex);
Please use a mutex, not a semaphore.
Quoted 25 lines
lib/dynamic_printk.c new file +25
-0+static int nr_entries; + +int dynamic_printk_enabled[NR_CPUS ]; +EXPORT_SYMBOL_GPL (dynamic_printk_enabled); + +struct debug_name { +struct hlist_node hlist; +char *name; +unsigned int num_uses; +int enable; +int flags; +int level; +int ratelimit; +}; + +static struct debug_name *find_debug_file (char *module_name) +{ +int found =0 ; +struct hlist_head *head; +struct hlist_node *node; +struct debug_name *element; + + head = &module_table[dynamic_name_hash (module_name)]; +rcu_read_lock (); +hlist_for_each_entry_rcu (element, node, head, hlist) {
lib/dynamic_printk.c line 60
Quoted 10 lines
lib/dynamic_printk.c new file +10
-0+if (!strcmp (element->name, module_name)) { + found =1 ; +break ; + } + } +rcu_read_unlock (); +if (found) +return element; +return NULL ; +}
Is the locking in here correct? We take the rcu_read_lock() then look up an item and then drop the lock and return a pointer to that item without having done anything to prevent that item from getting destroyed while this function's caller is playing with it.
lib/dynamic_printk.c line 72
Quoted 11 lines
lib/dynamic_printk.c new file +11
-0+static int add_debug_file (char *module_name) +{ +struct debug_name *new; + +if (find_debug_file (module_name)) +return -EINVAL ; + new =kzalloc (sizeof (struct debug_name ),GFP_KERNEL ); +if (!new) +return -ENOMEM ; +INIT_HLIST_NODE (&new->hlist); + new->name = module_name;
We saved away a pointer to something which can be independently destroyed?
Perhaps this can't happen because we'll destroy this dependency on the module removal path?
Some code comments here would help. Particularly around the data structures, the relationship between them and their locking requirements.
lib/dynamic_printk.c line 74
Quoted 2 lines
lib/dynamic_printk.c new file +2
-0+hlist_add_head_rcu (&new->hlist, + &module_table[dynamic_name_hash (new->name)]);
hlist_add_head_rcu() says:
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as hlist_add_head_rcu()
* or hlist_del_rcu(), running on this same list.
but afaict we didn't do that? Maybe debug_list_mutex provides all the locking here.
lib/dynamic_printk.c line 86
Quoted 12 lines
lib/dynamic_printk.c new file +12
-0+ nr_entries++; +return 0 ; +} + +void add_module (char *mod_name) +{ +struct debug_name *elem; +char *module_name; + + module_name =kmalloc (strlen (mod_name) +1 ,GFP_KERNEL ); + module_name =strcpy (module_name, mod_name); + module_name[strlen (mod_name)] ='\0' ;
kstrdup()?
Quoted 13 lines
lib/dynamic_printk.c new file +13
-0+/* add error checking */ +down (&debug_list_mutex); +add_debug_file (module_name); + elem =find_debug_file (module_name); + elem->num_uses++; +up (&debug_list_mutex); +} +EXPORT_SYMBOL_GPL (add_module); + +int remove_debug_file (char *module_name) +{ +struct debug_name *element; +
lib/dynamic_printk.c line 109
Quoted 10 lines
lib/dynamic_printk.c new file +10
-0+ element =find_debug_file (module_name); +if (element ==NULL ) +return -EINVAL ; +hlist_del_rcu (&element->hlist); +synchronize_rcu (); +kfree (element->name); +kfree (element); + nr_entries--; +return 0 ; +}
remove_debug_file() is a very general-sounding identifier. If you indeed intended to make it a global symbol then it should use a more specific name.
lib/dynamic_printk.c line 118
Quoted 8 lines
lib/dynamic_printk.c new file +8
-0+int remove_module (char *mod_name) +{ +down (&debug_list_mutex); +remove_debug_file (mod_name); +up (&debug_list_mutex); +return 0 ; +} +EXPORT_SYMBOL_GPL (remove_module);
Similarly, the identifiers add_module and remove_module are insufficiently specific.
lib/dynamic_printk.c line 128
Quoted 9 lines
lib/dynamic_printk.c new file +9
-0+#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG + +void dynamic_printk (char *module_name,char *fmt, ...) +{ +va_list args; +struct debug_name *elem; + +va_start (args, fmt); +if (elem =find_debug_file (module_name)) {
That will generate a `suggest parentheses around assignment used as truth value' warning, won't it?
The preferred style here is
elem = find_debug_file(module_name); if (elem)
lib/dynamic_printk.c line 136
Quoted 8 lines
lib/dynamic_printk.c new file +8
-0+if (elem->enable) +vprintk (fmt, args); + } +va_end (args); +} +EXPORT_SYMBOL_GPL (dynamic_printk); + +static void set_all (int enable)
It would be nice to have some introductory comments over these functions explaining their role in life.
Quoted 9 lines
lib/dynamic_printk.c new file +9
-0+{ +struct debug_name *e; +struct hlist_node *node; +int i, cpu, enable_mask; + +for (i =0 ; i <FILE_TABLE_SIZE ; i++) { +if (module_table[i].first !=NULL ) { +hlist_for_each_entry (e, node, &module_table[i], hlist) { + e->enable = enable;
lib/dynamic_printk.c line 155
Quoted 10 lines
lib/dynamic_printk.c new file +10
-0+ } + } + } +if (enable) + enable_mask =UINT_MAX ; +else + enable_mask =0 ; +for (i =0 ; i <NR_CPUS ; i++) + dynamic_printk_enabled[i] = enable_mask; +}
We prefer to avoid the use of NR_CPUS-sized per-cpu data structures. One some systems you will be iterating across 1024 elements on behalf of just two CPUs.
It's better to use the include/linux/percpu.h infrastructure and a CPU hotplug notifier.
lib/dynamic_printk.c line 158
Quoted 2 lines
lib/dynamic_printk.c new file +2
-0+#define enable_all () set_all(1) +#define disable_all () set_all(0)
Suggest that these be removed and open-coded at the callsites. If you make the argument to set_all() be a `bool' then
set_all(true);
and
set_all(false);
should be sufficiently clear. It'd become even better if a more meaningful name was used. set_all_bananas(true).
lib/dynamic_printk.c line 170
Quoted 11 lines
lib/dynamic_printk.c new file +11
-0+static int disabled_hash (int i) +{ +struct debug_name *e; +struct hlist_node *node; + +hlist_for_each_entry (e, node, &module_table[i], hlist) { +if (e->enable) +return 0 ; + } +return 1 ; +}
Needs a covering comment, please. Could return a `bool' type?
lib/dynamic_printk.c line 180
Quoted 9 lines
lib/dynamic_printk.c new file +9
-0+static ssize_t pr_debug_write (struct file *file,const char __user *buf, +size_t length,loff_t *ppos) +{ +char *buffer, *s; +int err, hash, i; +struct debug_name *elem; + +if (!buf || length >PAGE_SIZE || length <0 ) +return -EINVAL ;
The check for (buf == NULL) is incorrect. Just let it go through and if that is indeed an invalid user address, the copy_from_user() will give us the correct -EFAULT.
lib/dynamic_printk.c line 194
Quoted 13 lines
lib/dynamic_printk.c new file +13
-0+ 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;
Might be able to use strncpy_from_user() here somehow.
lib/dynamic_printk.c line 204
Quoted 9 lines
lib/dynamic_printk.c new file +9
-0+ err = -EINVAL ; +down (&debug_list_mutex); +if (!strncmp ("enable all" , buffer,10 )) { +if (nr_entries) { +enable_all (); + num_enabled = nr_entries; + err =0 ; + } + }else if (!strncmp ("disable all" , buffer,11 )) {
We accept "disable allwibble" as valid input.
sysfs_streq() will fix that.
Quoted 19 lines
lib/dynamic_printk.c new file +19
-0+disable_all (); + num_enabled =0 ; + err =0 ; + }else if (!strncmp ("enable " , buffer,7 )) { + s =strstrip (buffer +7 ); +if (elem =find_debug_file (s)) { +if (elem->enable ==0 ) { + hash =dynamic_name_hash (s); +for (i =0 ; i <NR_CPUS ; i++) + dynamic_printk_enabled[i] |= (1 << hash); + elem->enable =1 ; + num_enabled++; + } + err =0 ; + } + }else if (!strncmp ("disable " , buffer,8 )) { + s =strstrip (buffer +8 ); +if (elem =find_debug_file (s)) { +if (elem->enable ==1 ) {
lib/dynamic_printk.c line 233
Quoted 10 lines
lib/dynamic_printk.c new file +10
-0+ elem->enable =0 ; + num_enabled--; +if (disabled_hash (dynamic_name_hash (s))) { +for (i =0 ; i <NR_CPUS ; i++) + dynamic_printk_enabled[i] |= ~(1 << hash); + } + } + err =0 ; + } + }
The above might become simpler and cleaner if we had separate enable' and disable' control files.
lib/dynamic_printk.c line 239
Quoted 6 lines
lib/dynamic_printk.c new file +6
-0+if (!err) + err = length; + +up (&debug_list_mutex); +out: +free_page ((unsigned long )buffer);
Plain old kmalloc(PAGE_SIZE, GFP_KERNEL) might be nicer here.
Quoted 48 lines
lib/dynamic_printk.c new file +48
-0+return err; +} + +static void *pr_debug_seq_start (struct seq_file *f,loff_t *pos) +{ +return (*pos <FILE_TABLE_SIZE ) ? pos :NULL ; +} + +static void *pr_debug_seq_next (struct seq_file *s,void *v,loff_t *pos) +{ + (*pos)++; +if (*pos >=FILE_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 *element; +unsigned int i = *(loff_t *) v; + +rcu_read_lock (); + head = &module_table[i]; +hlist_for_each_entry_rcu (element, node, head, hlist) +seq_printf (s,"%s %d %d\n" , element->name, element->enable, + element->num_uses); +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); +}
lib/dynamic_printk.c line 297
Quoted 10 lines
lib/dynamic_printk.c new file +10
-0+ +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 )
Can be static?
Quoted 6 lines
lib/dynamic_printk.c new file +6
-0+{ +struct dentry *dir, *file; +struct mod_debug *iter; + + dir =debugfs_create_dir ("dynamic_printk" ,NULL ); +if (!dir)
lib/dynamic_printk.c line 313
Quoted 10 lines
lib/dynamic_printk.c new file +10
-0+return -ENOMEM ; + file =debugfs_create_file ("modules" ,0644 , dir,NULL , + &pr_debug_operations); +if (!file) { +debugfs_remove (dir); +return -ENOMEM ; + } +for (iter = __start___verbose; iter < __stop___verbose; iter++) { +add_module (iter->modname); + }
unneeded braces.
lib/dynamic_printk.c line 316
Quoted 3 lines
lib/dynamic_printk.c new file +3
-0+return 0 ; +} +__initcall (dynamic_printk_init);
__initcall is a bit old-fashioned. module_init() is the shiny new fashion.
lib/dynamic_printk.c line 325
Quoted 8 lines
lib/dynamic_printk.c new file +8
-0+static int __init dynamic_printk_setup (char *str) +{ +if (str) +return -ENOENT ; +set_all (1 ); +return 0 ; +} +early_param ("dynamic_printk" , dynamic_printk_setup);
Please add a comment telling the reader why early_param() was chosen here.