Commit bfe8df3d314bddf30758bd738e0087e80964760c
Committed by
Linus Torvalds
1 parent
1bcf548293
Exists in
master
and in
4 other branches
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>
Showing 5 changed files with 85 additions and 1 deletions Side-by-side Diff
Documentation/kernel-parameters.txt
... | ... | @@ -349,6 +349,11 @@ |
349 | 349 | blkmtd_bs= |
350 | 350 | blkmtd_count= |
351 | 351 | |
352 | + boot_delay= Milliseconds to delay each printk during boot. | |
353 | + Values larger than 10 seconds (10000) are changed to | |
354 | + no delay (0). | |
355 | + Format: integer | |
356 | + | |
352 | 357 | bttv.card= [HW,V4L] bttv (bt848 + bt878 based grabber cards) |
353 | 358 | bttv.radio= Most important insmod options are available as |
354 | 359 | kernel args too. |
include/linux/jiffies.h
... | ... | @@ -148,6 +148,8 @@ |
148 | 148 | */ |
149 | 149 | #define MAX_JIFFY_OFFSET ((LONG_MAX >> 1)-1) |
150 | 150 | |
151 | +extern unsigned long preset_lpj; | |
152 | + | |
151 | 153 | /* |
152 | 154 | * We want to do realistic conversions of time so we need to use the same |
153 | 155 | * values the update wall clock code uses as the jiffies size. This value |
init/calibrate.c
kernel/printk.c
... | ... | @@ -22,6 +22,8 @@ |
22 | 22 | #include <linux/tty_driver.h> |
23 | 23 | #include <linux/console.h> |
24 | 24 | #include <linux/init.h> |
25 | +#include <linux/jiffies.h> | |
26 | +#include <linux/nmi.h> | |
25 | 27 | #include <linux/module.h> |
26 | 28 | #include <linux/moduleparam.h> |
27 | 29 | #include <linux/interrupt.h> /* For in_interrupt() */ |
... | ... | @@ -162,6 +164,61 @@ |
162 | 164 | |
163 | 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 | 223 | * Commands to do_syslog: |
167 | 224 | * |
... | ... | @@ -526,6 +583,8 @@ |
526 | 583 | char *p; |
527 | 584 | static char printk_buf[1024]; |
528 | 585 | static int log_level_unknown = 1; |
586 | + | |
587 | + boot_delay_msec(); | |
529 | 588 | |
530 | 589 | preempt_disable(); |
531 | 590 | if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id()) |
lib/Kconfig.debug
... | ... | @@ -413,6 +413,24 @@ |
413 | 413 | become the default in the future, until then this option is there to |
414 | 414 | test gcc for this. |
415 | 415 | |
416 | +config BOOT_PRINTK_DELAY | |
417 | + bool "Delay each boot printk message by N milliseconds" | |
418 | + depends on DEBUG_KERNEL && PRINTK && GENERIC_CALIBRATE_DELAY | |
419 | + help | |
420 | + This build option allows you to read kernel boot messages | |
421 | + by inserting a short delay after each one. The delay is | |
422 | + specified in milliseconds on the kernel command line, | |
423 | + using "boot_delay=N". | |
424 | + | |
425 | + It is likely that you would also need to use "lpj=M" to preset | |
426 | + the "loops per jiffie" value. | |
427 | + See a previous boot log for the "lpj" value to use for your | |
428 | + system, and then set "lpj=M" before setting "boot_delay=N". | |
429 | + NOTE: Using this option may adversely affect SMP systems. | |
430 | + I.e., processors other than the first one may not boot up. | |
431 | + BOOT_PRINTK_DELAY also may cause DETECT_SOFTLOCKUP to detect | |
432 | + what it believes to be lockup conditions. | |
433 | + | |
416 | 434 | config RCU_TORTURE_TEST |
417 | 435 | tristate "torture tests for RCU" |
418 | 436 | depends on DEBUG_KERNEL |