aboutsummaryrefslogtreecommitdiffstats
path: root/init
diff options
context:
space:
mode:
authorPrarit Bhargava <prarit@redhat.com>2014-06-04 19:12:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-04 19:54:21 -0400
commit7b0b73d76651e5f88c88b76efa18d719f832bf6f (patch)
tree6a3fc7c9bf1e2efbd4c4188e3598cc786c541b7b /init
parentd62cf81524304396276f6aaa5cd7ce62f6f65110 (diff)
init/main.c: add initcall_blacklist kernel parameter
When a module is built into the kernel the module_init() function becomes an initcall. Sometimes debugging through dynamic debug can help, however, debugging built in kernel modules is typically done by changing the .config, recompiling, and booting the new kernel in an effort to determine exactly which module caused a problem. This patchset can be useful stand-alone or combined with initcall_debug. There are cases where some initcalls can hang the machine before the console can be flushed, which can make initcall_debug output inaccurate. Having the ability to skip initcalls can help further debugging of these scenarios. Usage: initcall_blacklist=<list of comma separated initcalls> ex) added "initcall_blacklist=sgi_uv_sysfs_init" as a kernel parameter and the log contains: blacklisting initcall sgi_uv_sysfs_init ... ... initcall sgi_uv_sysfs_init blacklisted ex) added "initcall_blacklist=foo_bar,sgi_uv_sysfs_init" as a kernel parameter and the log contains: blacklisting initcall foo_bar blacklisting initcall sgi_uv_sysfs_init ... ... initcall sgi_uv_sysfs_init blacklisted [akpm@linux-foundation.org: tweak printk text] Signed-off-by: Prarit Bhargava <prarit@redhat.com> Cc: Richard Weinberger <richard.weinberger@gmail.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Josh Boyer <jwboyer@fedoraproject.org> Cc: Rob Landley <rob@landley.net> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Ingo Molnar <mingo@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'init')
-rw-r--r--init/main.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/init/main.c b/init/main.c
index 9d3a7b84de5c..8ac3833f2bdf 100644
--- a/init/main.c
+++ b/init/main.c
@@ -77,6 +77,7 @@
77#include <linux/sched_clock.h> 77#include <linux/sched_clock.h>
78#include <linux/context_tracking.h> 78#include <linux/context_tracking.h>
79#include <linux/random.h> 79#include <linux/random.h>
80#include <linux/list.h>
80 81
81#include <asm/io.h> 82#include <asm/io.h>
82#include <asm/bugs.h> 83#include <asm/bugs.h>
@@ -665,6 +666,70 @@ static void __init do_ctors(void)
665bool initcall_debug; 666bool initcall_debug;
666core_param(initcall_debug, initcall_debug, bool, 0644); 667core_param(initcall_debug, initcall_debug, bool, 0644);
667 668
669#ifdef CONFIG_KALLSYMS
670struct blacklist_entry {
671 struct list_head next;
672 char *buf;
673};
674
675static __initdata_or_module LIST_HEAD(blacklisted_initcalls);
676
677static int __init initcall_blacklist(char *str)
678{
679 char *str_entry;
680 struct blacklist_entry *entry;
681
682 /* str argument is a comma-separated list of functions */
683 do {
684 str_entry = strsep(&str, ",");
685 if (str_entry) {
686 pr_debug("blacklisting initcall %s\n", str_entry);
687 entry = alloc_bootmem(sizeof(*entry));
688 entry->buf = alloc_bootmem(strlen(str_entry) + 1);
689 strcpy(entry->buf, str_entry);
690 list_add(&entry->next, &blacklisted_initcalls);
691 }
692 } while (str_entry);
693
694 return 0;
695}
696
697static bool __init_or_module initcall_blacklisted(initcall_t fn)
698{
699 struct list_head *tmp;
700 struct blacklist_entry *entry;
701 char *fn_name;
702
703 fn_name = kasprintf(GFP_KERNEL, "%pf", fn);
704 if (!fn_name)
705 return false;
706
707 list_for_each(tmp, &blacklisted_initcalls) {
708 entry = list_entry(tmp, struct blacklist_entry, next);
709 if (!strcmp(fn_name, entry->buf)) {
710 pr_debug("initcall %s blacklisted\n", fn_name);
711 kfree(fn_name);
712 return true;
713 }
714 }
715
716 kfree(fn_name);
717 return false;
718}
719#else
720static int __init initcall_blacklist(char *str)
721{
722 pr_warn("initcall_blacklist requires CONFIG_KALLSYMS\n");
723 return 0;
724}
725
726static bool __init_or_module initcall_blacklisted(initcall_t fn)
727{
728 return false;
729}
730#endif
731__setup("initcall_blacklist=", initcall_blacklist);
732
668static int __init_or_module do_one_initcall_debug(initcall_t fn) 733static int __init_or_module do_one_initcall_debug(initcall_t fn)
669{ 734{
670 ktime_t calltime, delta, rettime; 735 ktime_t calltime, delta, rettime;
@@ -689,6 +754,9 @@ int __init_or_module do_one_initcall(initcall_t fn)
689 int ret; 754 int ret;
690 char msgbuf[64]; 755 char msgbuf[64];
691 756
757 if (initcall_blacklisted(fn))
758 return -EPERM;
759
692 if (initcall_debug) 760 if (initcall_debug)
693 ret = do_one_initcall_debug(fn); 761 ret = do_one_initcall_debug(fn);
694 else 762 else