diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 88 |
1 files changed, 81 insertions, 7 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index b799a2ee96e..cbebc142be1 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -53,6 +53,10 @@ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...) | |||
53 | 53 | ||
54 | #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) | 54 | #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) |
55 | 55 | ||
56 | #ifdef CONFIG_DEBUG_LL | ||
57 | extern void printascii(char *); | ||
58 | #endif | ||
59 | |||
56 | /* printk's without a loglevel use this.. */ | 60 | /* printk's without a loglevel use this.. */ |
57 | #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL | 61 | #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL |
58 | 62 | ||
@@ -297,6 +301,53 @@ static inline void boot_delay_msec(void) | |||
297 | } | 301 | } |
298 | #endif | 302 | #endif |
299 | 303 | ||
304 | /* | ||
305 | * Return the number of unread characters in the log buffer. | ||
306 | */ | ||
307 | static int log_buf_get_len(void) | ||
308 | { | ||
309 | return logged_chars; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * Clears the ring-buffer | ||
314 | */ | ||
315 | void log_buf_clear(void) | ||
316 | { | ||
317 | logged_chars = 0; | ||
318 | } | ||
319 | |||
320 | /* | ||
321 | * Copy a range of characters from the log buffer. | ||
322 | */ | ||
323 | int log_buf_copy(char *dest, int idx, int len) | ||
324 | { | ||
325 | int ret, max; | ||
326 | bool took_lock = false; | ||
327 | |||
328 | if (!oops_in_progress) { | ||
329 | spin_lock_irq(&logbuf_lock); | ||
330 | took_lock = true; | ||
331 | } | ||
332 | |||
333 | max = log_buf_get_len(); | ||
334 | if (idx < 0 || idx >= max) { | ||
335 | ret = -1; | ||
336 | } else { | ||
337 | if (len > max - idx) | ||
338 | len = max - idx; | ||
339 | ret = len; | ||
340 | idx += (log_end - max); | ||
341 | while (len-- > 0) | ||
342 | dest[len] = LOG_BUF(idx + len); | ||
343 | } | ||
344 | |||
345 | if (took_lock) | ||
346 | spin_unlock_irq(&logbuf_lock); | ||
347 | |||
348 | return ret; | ||
349 | } | ||
350 | |||
300 | #ifdef CONFIG_SECURITY_DMESG_RESTRICT | 351 | #ifdef CONFIG_SECURITY_DMESG_RESTRICT |
301 | int dmesg_restrict = 1; | 352 | int dmesg_restrict = 1; |
302 | #else | 353 | #else |
@@ -325,8 +376,10 @@ static int check_syslog_permissions(int type, bool from_file) | |||
325 | return 0; | 376 | return 0; |
326 | /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */ | 377 | /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */ |
327 | if (capable(CAP_SYS_ADMIN)) { | 378 | if (capable(CAP_SYS_ADMIN)) { |
328 | WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN " | 379 | printk_once(KERN_WARNING "%s (%d): " |
329 | "but no CAP_SYSLOG (deprecated).\n"); | 380 | "Attempt to access syslog with CAP_SYS_ADMIN " |
381 | "but no CAP_SYSLOG (deprecated).\n", | ||
382 | current->comm, task_pid_nr(current)); | ||
330 | return 0; | 383 | return 0; |
331 | } | 384 | } |
332 | return -EPERM; | 385 | return -EPERM; |
@@ -789,7 +842,7 @@ static inline int can_use_console(unsigned int cpu) | |||
789 | static int console_trylock_for_printk(unsigned int cpu) | 842 | static int console_trylock_for_printk(unsigned int cpu) |
790 | __releases(&logbuf_lock) | 843 | __releases(&logbuf_lock) |
791 | { | 844 | { |
792 | int retval = 0; | 845 | int retval = 0, wake = 0; |
793 | 846 | ||
794 | if (console_trylock()) { | 847 | if (console_trylock()) { |
795 | retval = 1; | 848 | retval = 1; |
@@ -802,12 +855,14 @@ static int console_trylock_for_printk(unsigned int cpu) | |||
802 | */ | 855 | */ |
803 | if (!can_use_console(cpu)) { | 856 | if (!can_use_console(cpu)) { |
804 | console_locked = 0; | 857 | console_locked = 0; |
805 | up(&console_sem); | 858 | wake = 1; |
806 | retval = 0; | 859 | retval = 0; |
807 | } | 860 | } |
808 | } | 861 | } |
809 | printk_cpu = UINT_MAX; | 862 | printk_cpu = UINT_MAX; |
810 | spin_unlock(&logbuf_lock); | 863 | spin_unlock(&logbuf_lock); |
864 | if (wake) | ||
865 | up(&console_sem); | ||
811 | return retval; | 866 | return retval; |
812 | } | 867 | } |
813 | static const char recursion_bug_msg [] = | 868 | static const char recursion_bug_msg [] = |
@@ -882,6 +937,10 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
882 | if (trace_override && !trace_recurse) | 937 | if (trace_override && !trace_recurse) |
883 | TRACE("%s", printk_buf); | 938 | TRACE("%s", printk_buf); |
884 | 939 | ||
940 | #ifdef CONFIG_DEBUG_LL | ||
941 | printascii(printk_buf); | ||
942 | #endif | ||
943 | |||
885 | p = printk_buf; | 944 | p = printk_buf; |
886 | 945 | ||
887 | /* Read log level and handle special printk prefix */ | 946 | /* Read log level and handle special printk prefix */ |
@@ -1156,7 +1215,6 @@ static int __cpuinit console_cpu_notify(struct notifier_block *self, | |||
1156 | switch (action) { | 1215 | switch (action) { |
1157 | case CPU_ONLINE: | 1216 | case CPU_ONLINE: |
1158 | case CPU_DEAD: | 1217 | case CPU_DEAD: |
1159 | case CPU_DYING: | ||
1160 | case CPU_DOWN_FAILED: | 1218 | case CPU_DOWN_FAILED: |
1161 | case CPU_UP_CANCELED: | 1219 | case CPU_UP_CANCELED: |
1162 | console_lock(); | 1220 | console_lock(); |
@@ -1252,7 +1310,7 @@ void console_unlock(void) | |||
1252 | { | 1310 | { |
1253 | unsigned long flags; | 1311 | unsigned long flags; |
1254 | unsigned _con_start, _log_end; | 1312 | unsigned _con_start, _log_end; |
1255 | unsigned wake_klogd = 0; | 1313 | unsigned wake_klogd = 0, retry = 0; |
1256 | 1314 | ||
1257 | if (console_suspended) { | 1315 | if (console_suspended) { |
1258 | up(&console_sem); | 1316 | up(&console_sem); |
@@ -1261,6 +1319,7 @@ void console_unlock(void) | |||
1261 | 1319 | ||
1262 | console_may_schedule = 0; | 1320 | console_may_schedule = 0; |
1263 | 1321 | ||
1322 | again: | ||
1264 | for ( ; ; ) { | 1323 | for ( ; ; ) { |
1265 | spin_lock_irqsave(&logbuf_lock, flags); | 1324 | spin_lock_irqsave(&logbuf_lock, flags); |
1266 | wake_klogd |= log_start - log_end; | 1325 | wake_klogd |= log_start - log_end; |
@@ -1281,8 +1340,23 @@ void console_unlock(void) | |||
1281 | if (unlikely(exclusive_console)) | 1340 | if (unlikely(exclusive_console)) |
1282 | exclusive_console = NULL; | 1341 | exclusive_console = NULL; |
1283 | 1342 | ||
1343 | spin_unlock(&logbuf_lock); | ||
1344 | |||
1284 | up(&console_sem); | 1345 | up(&console_sem); |
1346 | |||
1347 | /* | ||
1348 | * Someone could have filled up the buffer again, so re-check if there's | ||
1349 | * something to flush. In case we cannot trylock the console_sem again, | ||
1350 | * there's a new owner and the console_unlock() from them will do the | ||
1351 | * flush, no worries. | ||
1352 | */ | ||
1353 | spin_lock(&logbuf_lock); | ||
1354 | if (con_start != log_end) | ||
1355 | retry = 1; | ||
1285 | spin_unlock_irqrestore(&logbuf_lock, flags); | 1356 | spin_unlock_irqrestore(&logbuf_lock, flags); |
1357 | if (retry && console_trylock()) | ||
1358 | goto again; | ||
1359 | |||
1286 | if (wake_klogd) | 1360 | if (wake_klogd) |
1287 | wake_up_klogd(); | 1361 | wake_up_klogd(); |
1288 | } | 1362 | } |
@@ -1594,7 +1668,7 @@ static int __init printk_late_init(void) | |||
1594 | struct console *con; | 1668 | struct console *con; |
1595 | 1669 | ||
1596 | for_each_console(con) { | 1670 | for_each_console(con) { |
1597 | if (con->flags & CON_BOOT) { | 1671 | if (!keep_bootcon && con->flags & CON_BOOT) { |
1598 | printk(KERN_INFO "turn off boot console %s%d\n", | 1672 | printk(KERN_INFO "turn off boot console %s%d\n", |
1599 | con->name, con->index); | 1673 | con->name, con->index); |
1600 | unregister_console(con); | 1674 | unregister_console(con); |