diff options
author | Randy Dunlap <rdunlap@xenotime.net> | 2007-10-16 04:23:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:42:49 -0400 |
commit | bfe8df3d314bddf30758bd738e0087e80964760c (patch) | |
tree | d04db4fb2592e2d416073681903f05f5b30f204b /kernel/printk.c | |
parent | 1bcf548293aef19b0797348332cf1dfbf2116cef (diff) |
slow down printk during boot
Optionally add a boot delay after each kernel printk() call, crudely
measured in milliseconds, with a maximum delay of 10 seconds per printk.
Enable CONFIG_BOOT_PRINTK_DELAY=y and then add (e.g.):
"lpj=loops_per_jiffy boot_delay=100"
to the kernel command line.
It has been useful in cases like "during boot, my machine just reboots or the
screen goes black" by slowing down printk, (and adding initcall_debug), we can
usually see the last thing that happened before the lights went out which is
usually a valuable clue.
[akpm@linux-foundation.org: not all architectures implement CONFIG_HZ]
[akpm@linux-foundation.org: fix lots of stuff]
[bunk@stusta.de: kernel/printk.c: make 2 variables static]
[heiko.carstens@de.ibm.com: fix slow down printk on boot compile error]
Signed-off-by: Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Dave Jones <davej@redhat.com>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 8451dfc31d25..b2b5c3a22a36 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/tty_driver.h> | 22 | #include <linux/tty_driver.h> |
23 | #include <linux/console.h> | 23 | #include <linux/console.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/jiffies.h> | ||
26 | #include <linux/nmi.h> | ||
25 | #include <linux/module.h> | 27 | #include <linux/module.h> |
26 | #include <linux/moduleparam.h> | 28 | #include <linux/moduleparam.h> |
27 | #include <linux/interrupt.h> /* For in_interrupt() */ | 29 | #include <linux/interrupt.h> /* For in_interrupt() */ |
@@ -162,6 +164,61 @@ out: | |||
162 | 164 | ||
163 | __setup("log_buf_len=", log_buf_len_setup); | 165 | __setup("log_buf_len=", log_buf_len_setup); |
164 | 166 | ||
167 | #ifdef CONFIG_BOOT_PRINTK_DELAY | ||
168 | |||
169 | static unsigned int boot_delay; /* msecs delay after each printk during bootup */ | ||
170 | static unsigned long long printk_delay_msec; /* per msec, based on boot_delay */ | ||
171 | |||
172 | static int __init boot_delay_setup(char *str) | ||
173 | { | ||
174 | unsigned long lpj; | ||
175 | unsigned long long loops_per_msec; | ||
176 | |||
177 | lpj = preset_lpj ? preset_lpj : 1000000; /* some guess */ | ||
178 | loops_per_msec = (unsigned long long)lpj / 1000 * HZ; | ||
179 | |||
180 | get_option(&str, &boot_delay); | ||
181 | if (boot_delay > 10 * 1000) | ||
182 | boot_delay = 0; | ||
183 | |||
184 | printk_delay_msec = loops_per_msec; | ||
185 | printk(KERN_DEBUG "boot_delay: %u, preset_lpj: %ld, lpj: %lu, " | ||
186 | "HZ: %d, printk_delay_msec: %llu\n", | ||
187 | boot_delay, preset_lpj, lpj, HZ, printk_delay_msec); | ||
188 | return 1; | ||
189 | } | ||
190 | __setup("boot_delay=", boot_delay_setup); | ||
191 | |||
192 | static void boot_delay_msec(void) | ||
193 | { | ||
194 | unsigned long long k; | ||
195 | unsigned long timeout; | ||
196 | |||
197 | if (boot_delay == 0 || system_state != SYSTEM_BOOTING) | ||
198 | return; | ||
199 | |||
200 | k = (unsigned long long)printk_delay_msec * boot_delay; | ||
201 | |||
202 | timeout = jiffies + msecs_to_jiffies(boot_delay); | ||
203 | while (k) { | ||
204 | k--; | ||
205 | cpu_relax(); | ||
206 | /* | ||
207 | * use (volatile) jiffies to prevent | ||
208 | * compiler reduction; loop termination via jiffies | ||
209 | * is secondary and may or may not happen. | ||
210 | */ | ||
211 | if (time_after(jiffies, timeout)) | ||
212 | break; | ||
213 | touch_nmi_watchdog(); | ||
214 | } | ||
215 | } | ||
216 | #else | ||
217 | static inline void boot_delay_msec(void) | ||
218 | { | ||
219 | } | ||
220 | #endif | ||
221 | |||
165 | /* | 222 | /* |
166 | * Commands to do_syslog: | 223 | * Commands to do_syslog: |
167 | * | 224 | * |
@@ -527,6 +584,8 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
527 | static char printk_buf[1024]; | 584 | static char printk_buf[1024]; |
528 | static int log_level_unknown = 1; | 585 | static int log_level_unknown = 1; |
529 | 586 | ||
587 | boot_delay_msec(); | ||
588 | |||
530 | preempt_disable(); | 589 | preempt_disable(); |
531 | if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id()) | 590 | if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id()) |
532 | /* If a crash is occurring during printk() on this CPU, | 591 | /* If a crash is occurring during printk() on this CPU, |