|
@@ -349,7 +349,7 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
|
|
|
*/
|
|
|
|
|
|
enum log_flags {
|
|
|
- LOG_NOCONS = 1, /* already flushed, do not print to console */
|
|
|
+ LOG_NOCONS = 1, /* suppress print, do not print to console */
|
|
|
LOG_NEWLINE = 2, /* text ended with a newline */
|
|
|
LOG_PREFIX = 4, /* text started with a prefix */
|
|
|
LOG_CONT = 8, /* text is a fragment of a continuation line */
|
|
@@ -1352,71 +1352,68 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
|
|
|
{
|
|
|
char *text;
|
|
|
int len = 0;
|
|
|
+ u64 next_seq;
|
|
|
+ u64 seq;
|
|
|
+ u32 idx;
|
|
|
|
|
|
text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL);
|
|
|
if (!text)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
logbuf_lock_irq();
|
|
|
- if (buf) {
|
|
|
- u64 next_seq;
|
|
|
- u64 seq;
|
|
|
- u32 idx;
|
|
|
+ /*
|
|
|
+ * Find first record that fits, including all following records,
|
|
|
+ * into the user-provided buffer for this dump.
|
|
|
+ */
|
|
|
+ seq = clear_seq;
|
|
|
+ idx = clear_idx;
|
|
|
+ while (seq < log_next_seq) {
|
|
|
+ struct printk_log *msg = log_from_idx(idx);
|
|
|
|
|
|
- /*
|
|
|
- * Find first record that fits, including all following records,
|
|
|
- * into the user-provided buffer for this dump.
|
|
|
- */
|
|
|
- seq = clear_seq;
|
|
|
- idx = clear_idx;
|
|
|
- while (seq < log_next_seq) {
|
|
|
- struct printk_log *msg = log_from_idx(idx);
|
|
|
-
|
|
|
- len += msg_print_text(msg, true, NULL, 0);
|
|
|
- idx = log_next(idx);
|
|
|
- seq++;
|
|
|
- }
|
|
|
+ len += msg_print_text(msg, true, NULL, 0);
|
|
|
+ idx = log_next(idx);
|
|
|
+ seq++;
|
|
|
+ }
|
|
|
|
|
|
- /* move first record forward until length fits into the buffer */
|
|
|
- seq = clear_seq;
|
|
|
- idx = clear_idx;
|
|
|
- while (len > size && seq < log_next_seq) {
|
|
|
- struct printk_log *msg = log_from_idx(idx);
|
|
|
+ /* move first record forward until length fits into the buffer */
|
|
|
+ seq = clear_seq;
|
|
|
+ idx = clear_idx;
|
|
|
+ while (len > size && seq < log_next_seq) {
|
|
|
+ struct printk_log *msg = log_from_idx(idx);
|
|
|
|
|
|
- len -= msg_print_text(msg, true, NULL, 0);
|
|
|
- idx = log_next(idx);
|
|
|
- seq++;
|
|
|
- }
|
|
|
+ len -= msg_print_text(msg, true, NULL, 0);
|
|
|
+ idx = log_next(idx);
|
|
|
+ seq++;
|
|
|
+ }
|
|
|
|
|
|
- /* last message fitting into this dump */
|
|
|
- next_seq = log_next_seq;
|
|
|
+ /* last message fitting into this dump */
|
|
|
+ next_seq = log_next_seq;
|
|
|
|
|
|
- len = 0;
|
|
|
- while (len >= 0 && seq < next_seq) {
|
|
|
- struct printk_log *msg = log_from_idx(idx);
|
|
|
- int textlen;
|
|
|
+ len = 0;
|
|
|
+ while (len >= 0 && seq < next_seq) {
|
|
|
+ struct printk_log *msg = log_from_idx(idx);
|
|
|
+ int textlen;
|
|
|
|
|
|
- textlen = msg_print_text(msg, true, text,
|
|
|
- LOG_LINE_MAX + PREFIX_MAX);
|
|
|
- if (textlen < 0) {
|
|
|
- len = textlen;
|
|
|
- break;
|
|
|
- }
|
|
|
- idx = log_next(idx);
|
|
|
- seq++;
|
|
|
+ textlen = msg_print_text(msg, true, text,
|
|
|
+ LOG_LINE_MAX + PREFIX_MAX);
|
|
|
+ if (textlen < 0) {
|
|
|
+ len = textlen;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ idx = log_next(idx);
|
|
|
+ seq++;
|
|
|
|
|
|
- logbuf_unlock_irq();
|
|
|
- if (copy_to_user(buf + len, text, textlen))
|
|
|
- len = -EFAULT;
|
|
|
- else
|
|
|
- len += textlen;
|
|
|
- logbuf_lock_irq();
|
|
|
-
|
|
|
- if (seq < log_first_seq) {
|
|
|
- /* messages are gone, move to next one */
|
|
|
- seq = log_first_seq;
|
|
|
- idx = log_first_idx;
|
|
|
- }
|
|
|
+ logbuf_unlock_irq();
|
|
|
+ if (copy_to_user(buf + len, text, textlen))
|
|
|
+ len = -EFAULT;
|
|
|
+ else
|
|
|
+ len += textlen;
|
|
|
+ logbuf_lock_irq();
|
|
|
+
|
|
|
+ if (seq < log_first_seq) {
|
|
|
+ /* messages are gone, move to next one */
|
|
|
+ seq = log_first_seq;
|
|
|
+ idx = log_first_idx;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1430,6 +1427,14 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
|
|
|
return len;
|
|
|
}
|
|
|
|
|
|
+static void syslog_clear(void)
|
|
|
+{
|
|
|
+ logbuf_lock_irq();
|
|
|
+ clear_seq = log_next_seq;
|
|
|
+ clear_idx = log_next_idx;
|
|
|
+ logbuf_unlock_irq();
|
|
|
+}
|
|
|
+
|
|
|
int do_syslog(int type, char __user *buf, int len, int source)
|
|
|
{
|
|
|
bool clear = false;
|
|
@@ -1474,7 +1479,7 @@ int do_syslog(int type, char __user *buf, int len, int source)
|
|
|
break;
|
|
|
/* Clear ring buffer */
|
|
|
case SYSLOG_ACTION_CLEAR:
|
|
|
- syslog_print_all(NULL, 0, true);
|
|
|
+ syslog_clear();
|
|
|
break;
|
|
|
/* Disable logging to console */
|
|
|
case SYSLOG_ACTION_CONSOLE_OFF:
|
|
@@ -1824,28 +1829,16 @@ static size_t log_output(int facility, int level, enum log_flags lflags, const c
|
|
|
return log_store(facility, level, lflags, 0, dict, dictlen, text, text_len);
|
|
|
}
|
|
|
|
|
|
-asmlinkage int vprintk_emit(int facility, int level,
|
|
|
- const char *dict, size_t dictlen,
|
|
|
- const char *fmt, va_list args)
|
|
|
+/* Must be called under logbuf_lock. */
|
|
|
+int vprintk_store(int facility, int level,
|
|
|
+ const char *dict, size_t dictlen,
|
|
|
+ const char *fmt, va_list args)
|
|
|
{
|
|
|
static char textbuf[LOG_LINE_MAX];
|
|
|
char *text = textbuf;
|
|
|
size_t text_len;
|
|
|
enum log_flags lflags = 0;
|
|
|
- unsigned long flags;
|
|
|
- int printed_len;
|
|
|
- bool in_sched = false;
|
|
|
|
|
|
- if (level == LOGLEVEL_SCHED) {
|
|
|
- level = LOGLEVEL_DEFAULT;
|
|
|
- in_sched = true;
|
|
|
- }
|
|
|
-
|
|
|
- boot_delay_msec(level);
|
|
|
- printk_delay();
|
|
|
-
|
|
|
- /* This stops the holder of console_sem just where we want him */
|
|
|
- logbuf_lock_irqsave(flags);
|
|
|
/*
|
|
|
* The printf needs to come first; we need the syslog
|
|
|
* prefix which might be passed-in as a parameter.
|
|
@@ -1886,8 +1879,32 @@ asmlinkage int vprintk_emit(int facility, int level,
|
|
|
if (dict)
|
|
|
lflags |= LOG_PREFIX|LOG_NEWLINE;
|
|
|
|
|
|
- printed_len = log_output(facility, level, lflags, dict, dictlen, text, text_len);
|
|
|
+ if (suppress_message_printing(level))
|
|
|
+ lflags |= LOG_NOCONS;
|
|
|
+
|
|
|
+ return log_output(facility, level, lflags,
|
|
|
+ dict, dictlen, text, text_len);
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage int vprintk_emit(int facility, int level,
|
|
|
+ const char *dict, size_t dictlen,
|
|
|
+ const char *fmt, va_list args)
|
|
|
+{
|
|
|
+ int printed_len;
|
|
|
+ bool in_sched = false;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ if (level == LOGLEVEL_SCHED) {
|
|
|
+ level = LOGLEVEL_DEFAULT;
|
|
|
+ in_sched = true;
|
|
|
+ }
|
|
|
|
|
|
+ boot_delay_msec(level);
|
|
|
+ printk_delay();
|
|
|
+
|
|
|
+ /* This stops the holder of console_sem just where we want him */
|
|
|
+ logbuf_lock_irqsave(flags);
|
|
|
+ printed_len = vprintk_store(facility, level, dict, dictlen, fmt, args);
|
|
|
logbuf_unlock_irqrestore(flags);
|
|
|
|
|
|
/* If called from the scheduler, we can not call up(). */
|
|
@@ -2013,7 +2030,6 @@ static void call_console_drivers(const char *ext_text, size_t ext_len,
|
|
|
const char *text, size_t len) {}
|
|
|
static size_t msg_print_text(const struct printk_log *msg,
|
|
|
bool syslog, char *buf, size_t size) { return 0; }
|
|
|
-static bool suppress_message_printing(int level) { return false; }
|
|
|
|
|
|
#endif /* CONFIG_PRINTK */
|
|
|
|
|
@@ -2349,11 +2365,10 @@ skip:
|
|
|
break;
|
|
|
|
|
|
msg = log_from_idx(console_idx);
|
|
|
- if (suppress_message_printing(msg->level)) {
|
|
|
+ if (msg->flags & LOG_NOCONS) {
|
|
|
/*
|
|
|
- * Skip record we have buffered and already printed
|
|
|
- * directly to the console when we received it, and
|
|
|
- * record that has level above the console loglevel.
|
|
|
+ * Skip record if !ignore_loglevel, and
|
|
|
+ * record has level above the console loglevel.
|
|
|
*/
|
|
|
console_idx = log_next(console_idx);
|
|
|
console_seq++;
|
|
@@ -2878,16 +2893,20 @@ void wake_up_klogd(void)
|
|
|
preempt_enable();
|
|
|
}
|
|
|
|
|
|
-int vprintk_deferred(const char *fmt, va_list args)
|
|
|
+void defer_console_output(void)
|
|
|
{
|
|
|
- int r;
|
|
|
-
|
|
|
- r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args);
|
|
|
-
|
|
|
preempt_disable();
|
|
|
__this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
|
|
|
irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
|
|
|
preempt_enable();
|
|
|
+}
|
|
|
+
|
|
|
+int vprintk_deferred(const char *fmt, va_list args)
|
|
|
+{
|
|
|
+ int r;
|
|
|
+
|
|
|
+ r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args);
|
|
|
+ defer_console_output();
|
|
|
|
|
|
return r;
|
|
|
}
|