diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 127 |
1 files changed, 125 insertions, 2 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 8451dfc31d25..a30fe33de395 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,113 @@ 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 | |||
222 | /* | ||
223 | * Return the number of unread characters in the log buffer. | ||
224 | */ | ||
225 | int log_buf_get_len(void) | ||
226 | { | ||
227 | return logged_chars; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Copy a range of characters from the log buffer. | ||
232 | */ | ||
233 | int log_buf_copy(char *dest, int idx, int len) | ||
234 | { | ||
235 | int ret, max; | ||
236 | bool took_lock = false; | ||
237 | |||
238 | if (!oops_in_progress) { | ||
239 | spin_lock_irq(&logbuf_lock); | ||
240 | took_lock = true; | ||
241 | } | ||
242 | |||
243 | max = log_buf_get_len(); | ||
244 | if (idx < 0 || idx >= max) { | ||
245 | ret = -1; | ||
246 | } else { | ||
247 | if (len > max) | ||
248 | len = max; | ||
249 | ret = len; | ||
250 | idx += (log_end - max); | ||
251 | while (len-- > 0) | ||
252 | dest[len] = LOG_BUF(idx + len); | ||
253 | } | ||
254 | |||
255 | if (took_lock) | ||
256 | spin_unlock_irq(&logbuf_lock); | ||
257 | |||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * Extract a single character from the log buffer. | ||
263 | */ | ||
264 | int log_buf_read(int idx) | ||
265 | { | ||
266 | char ret; | ||
267 | |||
268 | if (log_buf_copy(&ret, idx, 1) == 1) | ||
269 | return ret; | ||
270 | else | ||
271 | return -1; | ||
272 | } | ||
273 | |||
165 | /* | 274 | /* |
166 | * Commands to do_syslog: | 275 | * Commands to do_syslog: |
167 | * | 276 | * |
@@ -527,6 +636,8 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
527 | static char printk_buf[1024]; | 636 | static char printk_buf[1024]; |
528 | static int log_level_unknown = 1; | 637 | static int log_level_unknown = 1; |
529 | 638 | ||
639 | boot_delay_msec(); | ||
640 | |||
530 | preempt_disable(); | 641 | preempt_disable(); |
531 | if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id()) | 642 | if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id()) |
532 | /* If a crash is occurring during printk() on this CPU, | 643 | /* If a crash is occurring during printk() on this CPU, |
@@ -751,7 +862,16 @@ int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, cha | |||
751 | return -1; | 862 | return -1; |
752 | } | 863 | } |
753 | 864 | ||
754 | #ifndef CONFIG_DISABLE_CONSOLE_SUSPEND | 865 | int console_suspend_enabled = 1; |
866 | EXPORT_SYMBOL(console_suspend_enabled); | ||
867 | |||
868 | static int __init console_suspend_disable(char *str) | ||
869 | { | ||
870 | console_suspend_enabled = 0; | ||
871 | return 1; | ||
872 | } | ||
873 | __setup("no_console_suspend", console_suspend_disable); | ||
874 | |||
755 | /** | 875 | /** |
756 | * suspend_console - suspend the console subsystem | 876 | * suspend_console - suspend the console subsystem |
757 | * | 877 | * |
@@ -759,6 +879,8 @@ int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, cha | |||
759 | */ | 879 | */ |
760 | void suspend_console(void) | 880 | void suspend_console(void) |
761 | { | 881 | { |
882 | if (!console_suspend_enabled) | ||
883 | return; | ||
762 | printk("Suspending console(s)\n"); | 884 | printk("Suspending console(s)\n"); |
763 | acquire_console_sem(); | 885 | acquire_console_sem(); |
764 | console_suspended = 1; | 886 | console_suspended = 1; |
@@ -766,10 +888,11 @@ void suspend_console(void) | |||
766 | 888 | ||
767 | void resume_console(void) | 889 | void resume_console(void) |
768 | { | 890 | { |
891 | if (!console_suspend_enabled) | ||
892 | return; | ||
769 | console_suspended = 0; | 893 | console_suspended = 0; |
770 | release_console_sem(); | 894 | release_console_sem(); |
771 | } | 895 | } |
772 | #endif /* CONFIG_DISABLE_CONSOLE_SUSPEND */ | ||
773 | 896 | ||
774 | /** | 897 | /** |
775 | * acquire_console_sem - lock the console system for exclusive use. | 898 | * acquire_console_sem - lock the console system for exclusive use. |