diff options
| author | Andrew Morton <akpm@digeo.com> | 2003-03-28 03:18:04 -0800 |
|---|---|---|
| committer | Dave Jones <davej@tetrachloride.(none)> | 2003-03-28 03:18:04 -0800 |
| commit | a3fa4e811e89f670cd21ef8f67ad3ccffce14333 (patch) | |
| tree | 5c39340eb6b80cc9fab1424ccc6c4d6cda712de5 | |
| parent | edad54dce95e2ebc3ff0be0d8a99334789a6bf5a (diff) | |
[PATCH] initcall debug code
The patch is designed to help locate where the kernel is dying during the
startup sequence.
- Boot parameter "initcall_debug" causes the kernel to print out the
address of each initcall before calling it.
The kallsyms tables do not cover __init sections, so printing the
symbolic version of these symbols doesn't work. They need to be looked up
in System.map.
- Detect whether an initcall returns with interrupts disabled or with a
locking imbalance. If it does, complain and then try to fix it up.
| -rw-r--r-- | Documentation/kernel-parameters.txt | 4 | ||||
| -rw-r--r-- | init/main.c | 35 |
2 files changed, 35 insertions, 4 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 5ca7313a74d6..1e0b17303ed1 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -390,6 +390,10 @@ running once the system is up. Run specified binary instead of /sbin/init as init process. + initcall_debug [KNL] Trace initcalls as they are executed. Useful + for working out where the kernel is dying during + startup. + initrd= [BOOT] Specify the location of the initial ramdisk inport_irq= [HW] Inport (ATI XL and Microsoft) busmouse driver diff --git a/init/main.c b/init/main.c index c6367147fe29..6fdeca1aca67 100644 --- a/init/main.c +++ b/init/main.c @@ -463,6 +463,15 @@ asmlinkage void __init start_kernel(void) rest_init(); } +int __initdata initcall_debug; + +static int __init initcall_debug_setup(char *str) +{ + initcall_debug = 1; + return 1; +} +__setup("initcall_debug", initcall_debug_setup); + struct task_struct *child_reaper = &init_task; extern initcall_t __initcall_start, __initcall_end; @@ -470,12 +479,30 @@ extern initcall_t __initcall_start, __initcall_end; static void __init do_initcalls(void) { initcall_t *call; + int count = preempt_count(); + + for (call = &__initcall_start; call < &__initcall_end; call++) { + char *msg; + + if (initcall_debug) + printk("calling initcall 0x%p\n", *call); - call = &__initcall_start; - do { (*call)(); - call++; - } while (call < &__initcall_end); + + msg = NULL; + if (preempt_count() != count) { + msg = "preemption imbalance"; + preempt_count() = count; + } + if (irqs_disabled()) { + msg = "disabled interrupts"; + local_irq_enable(); + } + if (msg) { + printk("error in initcall at 0x%p: " + "returned with %s\n", *call, msg); + } + } /* Make sure there is no pending stuff from the initcall sequence */ flush_scheduled_work(); |
