aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--init/main.c68
2 files changed, 72 insertions, 0 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index adea3a22fa00..9973a7e2e0ac 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1312,6 +1312,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
1312 for working out where the kernel is dying during 1312 for working out where the kernel is dying during
1313 startup. 1313 startup.
1314 1314
1315 initcall_blacklist= [KNL] Do not execute a comma-separated list of
1316 initcall functions. Useful for debugging built-in
1317 modules and initcalls.
1318
1315 initrd= [BOOT] Specify the location of the initial ramdisk 1319 initrd= [BOOT] Specify the location of the initial ramdisk
1316 1320
1317 inport.irq= [HW] Inport (ATI XL and Microsoft) busmouse driver 1321 inport.irq= [HW] Inport (ATI XL and Microsoft) busmouse driver
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