mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									1bcf548293
								
							
						
					
					
						commit
						bfe8df3d31
					
				
					 5 changed files with 85 additions and 1 deletions
				
			
		| 
						 | 
					@ -349,6 +349,11 @@ and is between 256 and 4096 characters. It is defined in the file
 | 
				
			||||||
	blkmtd_bs=
 | 
						blkmtd_bs=
 | 
				
			||||||
	blkmtd_count=
 | 
						blkmtd_count=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						boot_delay=	Milliseconds to delay each printk during boot.
 | 
				
			||||||
 | 
								Values larger than 10 seconds (10000) are changed to
 | 
				
			||||||
 | 
								no delay (0).
 | 
				
			||||||
 | 
								Format: integer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bttv.card=	[HW,V4L] bttv (bt848 + bt878 based grabber cards)
 | 
						bttv.card=	[HW,V4L] bttv (bt848 + bt878 based grabber cards)
 | 
				
			||||||
	bttv.radio=	Most important insmod options are available as
 | 
						bttv.radio=	Most important insmod options are available as
 | 
				
			||||||
			kernel args too.
 | 
								kernel args too.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -148,6 +148,8 @@ static inline u64 get_jiffies_64(void)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define MAX_JIFFY_OFFSET ((LONG_MAX >> 1)-1)
 | 
					#define MAX_JIFFY_OFFSET ((LONG_MAX >> 1)-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern unsigned long preset_lpj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * We want to do realistic conversions of time so we need to use the same
 | 
					 * We want to do realistic conversions of time so we need to use the same
 | 
				
			||||||
 * values the update wall clock code uses as the jiffies size.  This value
 | 
					 * values the update wall clock code uses as the jiffies size.  This value
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/timex.h>
 | 
					#include <asm/timex.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned long preset_lpj;
 | 
					unsigned long preset_lpj;
 | 
				
			||||||
static int __init lpj_setup(char *str)
 | 
					static int __init lpj_setup(char *str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	preset_lpj = simple_strtoul(str,NULL,0);
 | 
						preset_lpj = simple_strtoul(str,NULL,0);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,8 @@
 | 
				
			||||||
#include <linux/tty_driver.h>
 | 
					#include <linux/tty_driver.h>
 | 
				
			||||||
#include <linux/console.h>
 | 
					#include <linux/console.h>
 | 
				
			||||||
#include <linux/init.h>
 | 
					#include <linux/init.h>
 | 
				
			||||||
 | 
					#include <linux/jiffies.h>
 | 
				
			||||||
 | 
					#include <linux/nmi.h>
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/moduleparam.h>
 | 
					#include <linux/moduleparam.h>
 | 
				
			||||||
#include <linux/interrupt.h>			/* For in_interrupt() */
 | 
					#include <linux/interrupt.h>			/* For in_interrupt() */
 | 
				
			||||||
| 
						 | 
					@ -162,6 +164,61 @@ static int __init log_buf_len_setup(char *str)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__setup("log_buf_len=", log_buf_len_setup);
 | 
					__setup("log_buf_len=", log_buf_len_setup);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_BOOT_PRINTK_DELAY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned int boot_delay; /* msecs delay after each printk during bootup */
 | 
				
			||||||
 | 
					static unsigned long long printk_delay_msec; /* per msec, based on boot_delay */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __init boot_delay_setup(char *str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long lpj;
 | 
				
			||||||
 | 
						unsigned long long loops_per_msec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lpj = preset_lpj ? preset_lpj : 1000000;	/* some guess */
 | 
				
			||||||
 | 
						loops_per_msec = (unsigned long long)lpj / 1000 * HZ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						get_option(&str, &boot_delay);
 | 
				
			||||||
 | 
						if (boot_delay > 10 * 1000)
 | 
				
			||||||
 | 
							boot_delay = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printk_delay_msec = loops_per_msec;
 | 
				
			||||||
 | 
						printk(KERN_DEBUG "boot_delay: %u, preset_lpj: %ld, lpj: %lu, "
 | 
				
			||||||
 | 
							"HZ: %d, printk_delay_msec: %llu\n",
 | 
				
			||||||
 | 
							boot_delay, preset_lpj, lpj, HZ, printk_delay_msec);
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					__setup("boot_delay=", boot_delay_setup);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void boot_delay_msec(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long long k;
 | 
				
			||||||
 | 
						unsigned long timeout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (boot_delay == 0 || system_state != SYSTEM_BOOTING)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						k = (unsigned long long)printk_delay_msec * boot_delay;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						timeout = jiffies + msecs_to_jiffies(boot_delay);
 | 
				
			||||||
 | 
						while (k) {
 | 
				
			||||||
 | 
							k--;
 | 
				
			||||||
 | 
							cpu_relax();
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * use (volatile) jiffies to prevent
 | 
				
			||||||
 | 
							 * compiler reduction; loop termination via jiffies
 | 
				
			||||||
 | 
							 * is secondary and may or may not happen.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (time_after(jiffies, timeout))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							touch_nmi_watchdog();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static inline void boot_delay_msec(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Commands to do_syslog:
 | 
					 * Commands to do_syslog:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -527,6 +584,8 @@ asmlinkage int vprintk(const char *fmt, va_list args)
 | 
				
			||||||
	static char printk_buf[1024];
 | 
						static char printk_buf[1024];
 | 
				
			||||||
	static int log_level_unknown = 1;
 | 
						static int log_level_unknown = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						boot_delay_msec();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	preempt_disable();
 | 
						preempt_disable();
 | 
				
			||||||
	if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id())
 | 
						if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id())
 | 
				
			||||||
		/* If a crash is occurring during printk() on this CPU,
 | 
							/* If a crash is occurring during printk() on this CPU,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -413,6 +413,24 @@ config FORCED_INLINING
 | 
				
			||||||
	  become the default in the future, until then this option is there to
 | 
						  become the default in the future, until then this option is there to
 | 
				
			||||||
	  test gcc for this.
 | 
						  test gcc for this.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config BOOT_PRINTK_DELAY
 | 
				
			||||||
 | 
						bool "Delay each boot printk message by N milliseconds"
 | 
				
			||||||
 | 
						depends on DEBUG_KERNEL && PRINTK && GENERIC_CALIBRATE_DELAY
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  This build option allows you to read kernel boot messages
 | 
				
			||||||
 | 
						  by inserting a short delay after each one.  The delay is
 | 
				
			||||||
 | 
						  specified in milliseconds on the kernel command line,
 | 
				
			||||||
 | 
						  using "boot_delay=N".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  It is likely that you would also need to use "lpj=M" to preset
 | 
				
			||||||
 | 
						  the "loops per jiffie" value.
 | 
				
			||||||
 | 
						  See a previous boot log for the "lpj" value to use for your
 | 
				
			||||||
 | 
						  system, and then set "lpj=M" before setting "boot_delay=N".
 | 
				
			||||||
 | 
						  NOTE:  Using this option may adversely affect SMP systems.
 | 
				
			||||||
 | 
						  I.e., processors other than the first one may not boot up.
 | 
				
			||||||
 | 
						  BOOT_PRINTK_DELAY also may cause DETECT_SOFTLOCKUP to detect
 | 
				
			||||||
 | 
						  what it believes to be lockup conditions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config RCU_TORTURE_TEST
 | 
					config RCU_TORTURE_TEST
 | 
				
			||||||
	tristate "torture tests for RCU"
 | 
						tristate "torture tests for RCU"
 | 
				
			||||||
	depends on DEBUG_KERNEL
 | 
						depends on DEBUG_KERNEL
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue