aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRandy Dunlap <rdunlap@xenotime.net>2007-10-16 04:23:46 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 12:42:49 -0400
commitbfe8df3d314bddf30758bd738e0087e80964760c (patch)
treed04db4fb2592e2d416073681903f05f5b30f204b
parent1bcf548293aef19b0797348332cf1dfbf2116cef (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>
-rw-r--r--Documentation/kernel-parameters.txt5
-rw-r--r--include/linux/jiffies.h2
-rw-r--r--init/calibrate.c2
-rw-r--r--kernel/printk.c59
-rw-r--r--lib/Kconfig.debug18
5 files changed, 85 insertions, 1 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 085e4a095eaa..760ed5776174 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -349,6 +349,11 @@ and is between 256 and 4096 characters. It is defined in the file
349 blkmtd_bs= 349 blkmtd_bs=
350 blkmtd_count= 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 bttv.card= [HW,V4L] bttv (bt848 + bt878 based grabber cards) 357 bttv.card= [HW,V4L] bttv (bt848 + bt878 based grabber cards)
353 bttv.radio= Most important insmod options are available as 358 bttv.radio= Most important insmod options are available as
354 kernel args too. 359 kernel args too.
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index e757a74b9d17..8b080024bbc1 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -148,6 +148,8 @@ static inline u64 get_jiffies_64(void)
148 */ 148 */
149#define MAX_JIFFY_OFFSET ((LONG_MAX >> 1)-1) 149#define MAX_JIFFY_OFFSET ((LONG_MAX >> 1)-1)
150 150
151extern unsigned long preset_lpj;
152
151/* 153/*
152 * We want to do realistic conversions of time so we need to use the same 154 * We want to do realistic conversions of time so we need to use the same
153 * values the update wall clock code uses as the jiffies size. This value 155 * values the update wall clock code uses as the jiffies size. This value
diff --git a/init/calibrate.c b/init/calibrate.c
index 40ff3b404895..2d3d73bd4ce1 100644
--- a/init/calibrate.c
+++ b/init/calibrate.c
@@ -10,7 +10,7 @@
10 10
11#include <asm/timex.h> 11#include <asm/timex.h>
12 12
13static unsigned long preset_lpj; 13unsigned long preset_lpj;
14static int __init lpj_setup(char *str) 14static int __init lpj_setup(char *str)
15{ 15{
16 preset_lpj = simple_strtoul(str,NULL,0); 16 preset_lpj = simple_strtoul(str,NULL,0);
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
169static unsigned int boot_delay; /* msecs delay after each printk during bootup */
170static unsigned long long printk_delay_msec; /* per msec, based on boot_delay */
171
172static 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
192static 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
217static 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,
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 396c38b3cb69..7d16e6433302 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -413,6 +413,24 @@ config FORCED_INLINING
413 become the default in the future, until then this option is there to 413 become the default in the future, until then this option is there to
414 test gcc for this. 414 test gcc for this.
415 415
416config 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
416config RCU_TORTURE_TEST 434config RCU_TORTURE_TEST
417 tristate "torture tests for RCU" 435 tristate "torture tests for RCU"
418 depends on DEBUG_KERNEL 436 depends on DEBUG_KERNEL