|
@@ -194,8 +194,10 @@ static int console_may_schedule;
|
|
|
*/
|
|
|
|
|
|
enum log_flags {
|
|
|
- LOG_DEFAULT = 0,
|
|
|
- LOG_NOCONS = 1, /* already flushed, do not print to console */
|
|
|
+ LOG_NOCONS = 1, /* already flushed, 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 */
|
|
|
};
|
|
|
|
|
|
struct log {
|
|
@@ -217,6 +219,8 @@ static DEFINE_RAW_SPINLOCK(logbuf_lock);
|
|
|
/* the next printk record to read by syslog(READ) or /proc/kmsg */
|
|
|
static u64 syslog_seq;
|
|
|
static u32 syslog_idx;
|
|
|
+static enum log_flags syslog_prev;
|
|
|
+static size_t syslog_partial;
|
|
|
|
|
|
/* index and sequence number of the first record stored in the buffer */
|
|
|
static u64 log_first_seq;
|
|
@@ -430,20 +434,20 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
|
|
|
ret = mutex_lock_interruptible(&user->lock);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
- raw_spin_lock(&logbuf_lock);
|
|
|
+ raw_spin_lock_irq(&logbuf_lock);
|
|
|
while (user->seq == log_next_seq) {
|
|
|
if (file->f_flags & O_NONBLOCK) {
|
|
|
ret = -EAGAIN;
|
|
|
- raw_spin_unlock(&logbuf_lock);
|
|
|
+ raw_spin_unlock_irq(&logbuf_lock);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- raw_spin_unlock(&logbuf_lock);
|
|
|
+ raw_spin_unlock_irq(&logbuf_lock);
|
|
|
ret = wait_event_interruptible(log_wait,
|
|
|
user->seq != log_next_seq);
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
- raw_spin_lock(&logbuf_lock);
|
|
|
+ raw_spin_lock_irq(&logbuf_lock);
|
|
|
}
|
|
|
|
|
|
if (user->seq < log_first_seq) {
|
|
@@ -451,7 +455,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
|
|
|
user->idx = log_first_idx;
|
|
|
user->seq = log_first_seq;
|
|
|
ret = -EPIPE;
|
|
|
- raw_spin_unlock(&logbuf_lock);
|
|
|
+ raw_spin_unlock_irq(&logbuf_lock);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
@@ -465,7 +469,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
|
|
|
for (i = 0; i < msg->text_len; i++) {
|
|
|
unsigned char c = log_text(msg)[i];
|
|
|
|
|
|
- if (c < ' ' || c >= 128)
|
|
|
+ if (c < ' ' || c >= 127 || c == '\\')
|
|
|
len += sprintf(user->buf + len, "\\x%02x", c);
|
|
|
else
|
|
|
user->buf[len++] = c;
|
|
@@ -489,7 +493,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- if (c < ' ' || c >= 128) {
|
|
|
+ if (c < ' ' || c >= 127 || c == '\\') {
|
|
|
len += sprintf(user->buf + len, "\\x%02x", c);
|
|
|
continue;
|
|
|
}
|
|
@@ -501,7 +505,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
|
|
|
|
|
|
user->idx = log_next(user->idx);
|
|
|
user->seq++;
|
|
|
- raw_spin_unlock(&logbuf_lock);
|
|
|
+ raw_spin_unlock_irq(&logbuf_lock);
|
|
|
|
|
|
if (len > count) {
|
|
|
ret = -EINVAL;
|
|
@@ -528,7 +532,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
|
|
|
if (offset)
|
|
|
return -ESPIPE;
|
|
|
|
|
|
- raw_spin_lock(&logbuf_lock);
|
|
|
+ raw_spin_lock_irq(&logbuf_lock);
|
|
|
switch (whence) {
|
|
|
case SEEK_SET:
|
|
|
/* the first record */
|
|
@@ -552,7 +556,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
|
|
|
default:
|
|
|
ret = -EINVAL;
|
|
|
}
|
|
|
- raw_spin_unlock(&logbuf_lock);
|
|
|
+ raw_spin_unlock_irq(&logbuf_lock);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -566,14 +570,14 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
|
|
|
|
|
|
poll_wait(file, &log_wait, wait);
|
|
|
|
|
|
- raw_spin_lock(&logbuf_lock);
|
|
|
+ raw_spin_lock_irq(&logbuf_lock);
|
|
|
if (user->seq < log_next_seq) {
|
|
|
/* return error when data has vanished underneath us */
|
|
|
if (user->seq < log_first_seq)
|
|
|
ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
|
|
|
ret = POLLIN|POLLRDNORM;
|
|
|
}
|
|
|
- raw_spin_unlock(&logbuf_lock);
|
|
|
+ raw_spin_unlock_irq(&logbuf_lock);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -597,10 +601,10 @@ static int devkmsg_open(struct inode *inode, struct file *file)
|
|
|
|
|
|
mutex_init(&user->lock);
|
|
|
|
|
|
- raw_spin_lock(&logbuf_lock);
|
|
|
+ raw_spin_lock_irq(&logbuf_lock);
|
|
|
user->idx = log_first_idx;
|
|
|
user->seq = log_first_seq;
|
|
|
- raw_spin_unlock(&logbuf_lock);
|
|
|
+ raw_spin_unlock_irq(&logbuf_lock);
|
|
|
|
|
|
file->private_data = user;
|
|
|
return 0;
|
|
@@ -818,15 +822,18 @@ static size_t print_time(u64 ts, char *buf)
|
|
|
static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
|
|
|
{
|
|
|
size_t len = 0;
|
|
|
+ unsigned int prefix = (msg->facility << 3) | msg->level;
|
|
|
|
|
|
if (syslog) {
|
|
|
if (buf) {
|
|
|
- len += sprintf(buf, "<%u>", msg->level);
|
|
|
+ len += sprintf(buf, "<%u>", prefix);
|
|
|
} else {
|
|
|
len += 3;
|
|
|
- if (msg->level > 9)
|
|
|
- len++;
|
|
|
- if (msg->level > 99)
|
|
|
+ if (prefix > 999)
|
|
|
+ len += 3;
|
|
|
+ else if (prefix > 99)
|
|
|
+ len += 2;
|
|
|
+ else if (prefix > 9)
|
|
|
len++;
|
|
|
}
|
|
|
}
|
|
@@ -835,13 +842,26 @@ static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
|
|
|
return len;
|
|
|
}
|
|
|
|
|
|
-static size_t msg_print_text(const struct log *msg, bool syslog,
|
|
|
- char *buf, size_t size)
|
|
|
+static size_t msg_print_text(const struct log *msg, enum log_flags prev,
|
|
|
+ bool syslog, char *buf, size_t size)
|
|
|
{
|
|
|
const char *text = log_text(msg);
|
|
|
size_t text_size = msg->text_len;
|
|
|
+ bool prefix = true;
|
|
|
+ bool newline = true;
|
|
|
size_t len = 0;
|
|
|
|
|
|
+ if ((prev & LOG_CONT) && !(msg->flags & LOG_PREFIX))
|
|
|
+ prefix = false;
|
|
|
+
|
|
|
+ if (msg->flags & LOG_CONT) {
|
|
|
+ if ((prev & LOG_CONT) && !(prev & LOG_NEWLINE))
|
|
|
+ prefix = false;
|
|
|
+
|
|
|
+ if (!(msg->flags & LOG_NEWLINE))
|
|
|
+ newline = false;
|
|
|
+ }
|
|
|
+
|
|
|
do {
|
|
|
const char *next = memchr(text, '\n', text_size);
|
|
|
size_t text_len;
|
|
@@ -859,16 +879,22 @@ static size_t msg_print_text(const struct log *msg, bool syslog,
|
|
|
text_len + 1>= size - len)
|
|
|
break;
|
|
|
|
|
|
- len += print_prefix(msg, syslog, buf + len);
|
|
|
+ if (prefix)
|
|
|
+ len += print_prefix(msg, syslog, buf + len);
|
|
|
memcpy(buf + len, text, text_len);
|
|
|
len += text_len;
|
|
|
- buf[len++] = '\n';
|
|
|
+ if (next || newline)
|
|
|
+ buf[len++] = '\n';
|
|
|
} else {
|
|
|
/* SYSLOG_ACTION_* buffer size only calculation */
|
|
|
- len += print_prefix(msg, syslog, NULL);
|
|
|
- len += text_len + 1;
|
|
|
+ if (prefix)
|
|
|
+ len += print_prefix(msg, syslog, NULL);
|
|
|
+ len += text_len;
|
|
|
+ if (next || newline)
|
|
|
+ len++;
|
|
|
}
|
|
|
|
|
|
+ prefix = true;
|
|
|
text = next;
|
|
|
} while (text);
|
|
|
|
|
@@ -887,22 +913,35 @@ static int syslog_print(char __user *buf, int size)
|
|
|
|
|
|
while (size > 0) {
|
|
|
size_t n;
|
|
|
+ size_t skip;
|
|
|
|
|
|
raw_spin_lock_irq(&logbuf_lock);
|
|
|
if (syslog_seq < log_first_seq) {
|
|
|
/* messages are gone, move to first one */
|
|
|
syslog_seq = log_first_seq;
|
|
|
syslog_idx = log_first_idx;
|
|
|
+ syslog_prev = 0;
|
|
|
+ syslog_partial = 0;
|
|
|
}
|
|
|
if (syslog_seq == log_next_seq) {
|
|
|
raw_spin_unlock_irq(&logbuf_lock);
|
|
|
break;
|
|
|
}
|
|
|
+
|
|
|
+ skip = syslog_partial;
|
|
|
msg = log_from_idx(syslog_idx);
|
|
|
- n = msg_print_text(msg, true, text, LOG_LINE_MAX);
|
|
|
- if (n <= size) {
|
|
|
+ n = msg_print_text(msg, syslog_prev, true, text, LOG_LINE_MAX);
|
|
|
+ if (n - syslog_partial <= size) {
|
|
|
+ /* message fits into buffer, move forward */
|
|
|
syslog_idx = log_next(syslog_idx);
|
|
|
syslog_seq++;
|
|
|
+ syslog_prev = msg->flags;
|
|
|
+ n -= syslog_partial;
|
|
|
+ syslog_partial = 0;
|
|
|
+ } else if (!len){
|
|
|
+ /* partial read(), remember position */
|
|
|
+ n = size;
|
|
|
+ syslog_partial += n;
|
|
|
} else
|
|
|
n = 0;
|
|
|
raw_spin_unlock_irq(&logbuf_lock);
|
|
@@ -910,17 +949,15 @@ static int syslog_print(char __user *buf, int size)
|
|
|
if (!n)
|
|
|
break;
|
|
|
|
|
|
- len += n;
|
|
|
- size -= n;
|
|
|
- buf += n;
|
|
|
- n = copy_to_user(buf - n, text, n);
|
|
|
-
|
|
|
- if (n) {
|
|
|
- len -= n;
|
|
|
+ if (copy_to_user(buf, text + skip, n)) {
|
|
|
if (!len)
|
|
|
len = -EFAULT;
|
|
|
break;
|
|
|
}
|
|
|
+
|
|
|
+ len += n;
|
|
|
+ size -= n;
|
|
|
+ buf += n;
|
|
|
}
|
|
|
|
|
|
kfree(text);
|
|
@@ -941,6 +978,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
|
|
|
u64 next_seq;
|
|
|
u64 seq;
|
|
|
u32 idx;
|
|
|
+ enum log_flags prev;
|
|
|
|
|
|
if (clear_seq < log_first_seq) {
|
|
|
/* messages are gone, move to first available one */
|
|
@@ -954,10 +992,11 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
|
|
|
*/
|
|
|
seq = clear_seq;
|
|
|
idx = clear_idx;
|
|
|
+ prev = 0;
|
|
|
while (seq < log_next_seq) {
|
|
|
struct log *msg = log_from_idx(idx);
|
|
|
|
|
|
- len += msg_print_text(msg, true, NULL, 0);
|
|
|
+ len += msg_print_text(msg, prev, true, NULL, 0);
|
|
|
idx = log_next(idx);
|
|
|
seq++;
|
|
|
}
|
|
@@ -965,10 +1004,11 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
|
|
|
/* move first record forward until length fits into the buffer */
|
|
|
seq = clear_seq;
|
|
|
idx = clear_idx;
|
|
|
+ prev = 0;
|
|
|
while (len > size && seq < log_next_seq) {
|
|
|
struct log *msg = log_from_idx(idx);
|
|
|
|
|
|
- len -= msg_print_text(msg, true, NULL, 0);
|
|
|
+ len -= msg_print_text(msg, prev, true, NULL, 0);
|
|
|
idx = log_next(idx);
|
|
|
seq++;
|
|
|
}
|
|
@@ -977,17 +1017,19 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
|
|
|
next_seq = log_next_seq;
|
|
|
|
|
|
len = 0;
|
|
|
+ prev = 0;
|
|
|
while (len >= 0 && seq < next_seq) {
|
|
|
struct log *msg = log_from_idx(idx);
|
|
|
int textlen;
|
|
|
|
|
|
- textlen = msg_print_text(msg, true, text, LOG_LINE_MAX);
|
|
|
+ textlen = msg_print_text(msg, prev, true, text, LOG_LINE_MAX);
|
|
|
if (textlen < 0) {
|
|
|
len = textlen;
|
|
|
break;
|
|
|
}
|
|
|
idx = log_next(idx);
|
|
|
seq++;
|
|
|
+ prev = msg->flags;
|
|
|
|
|
|
raw_spin_unlock_irq(&logbuf_lock);
|
|
|
if (copy_to_user(buf + len, text, textlen))
|
|
@@ -1000,6 +1042,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
|
|
|
/* messages are gone, move to next one */
|
|
|
seq = log_first_seq;
|
|
|
idx = log_first_idx;
|
|
|
+ prev = 0;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -1018,7 +1061,6 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
|
|
|
{
|
|
|
bool clear = false;
|
|
|
static int saved_console_loglevel = -1;
|
|
|
- static DEFINE_MUTEX(syslog_mutex);
|
|
|
int error;
|
|
|
|
|
|
error = check_syslog_permissions(type, from_file);
|
|
@@ -1045,17 +1087,11 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
|
|
|
error = -EFAULT;
|
|
|
goto out;
|
|
|
}
|
|
|
- error = mutex_lock_interruptible(&syslog_mutex);
|
|
|
- if (error)
|
|
|
- goto out;
|
|
|
error = wait_event_interruptible(log_wait,
|
|
|
syslog_seq != log_next_seq);
|
|
|
- if (error) {
|
|
|
- mutex_unlock(&syslog_mutex);
|
|
|
+ if (error)
|
|
|
goto out;
|
|
|
- }
|
|
|
error = syslog_print(buf, len);
|
|
|
- mutex_unlock(&syslog_mutex);
|
|
|
break;
|
|
|
/* Read/clear last kernel messages */
|
|
|
case SYSLOG_ACTION_READ_CLEAR:
|
|
@@ -1111,6 +1147,8 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
|
|
|
/* messages are gone, move to first one */
|
|
|
syslog_seq = log_first_seq;
|
|
|
syslog_idx = log_first_idx;
|
|
|
+ syslog_prev = 0;
|
|
|
+ syslog_partial = 0;
|
|
|
}
|
|
|
if (from_file) {
|
|
|
/*
|
|
@@ -1120,19 +1158,20 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
|
|
|
*/
|
|
|
error = log_next_idx - syslog_idx;
|
|
|
} else {
|
|
|
- u64 seq;
|
|
|
- u32 idx;
|
|
|
+ u64 seq = syslog_seq;
|
|
|
+ u32 idx = syslog_idx;
|
|
|
+ enum log_flags prev = syslog_prev;
|
|
|
|
|
|
error = 0;
|
|
|
- seq = syslog_seq;
|
|
|
- idx = syslog_idx;
|
|
|
while (seq < log_next_seq) {
|
|
|
struct log *msg = log_from_idx(idx);
|
|
|
|
|
|
- error += msg_print_text(msg, true, NULL, 0);
|
|
|
+ error += msg_print_text(msg, prev, true, NULL, 0);
|
|
|
idx = log_next(idx);
|
|
|
seq++;
|
|
|
+ prev = msg->flags;
|
|
|
}
|
|
|
+ error -= syslog_partial;
|
|
|
}
|
|
|
raw_spin_unlock_irq(&logbuf_lock);
|
|
|
break;
|
|
@@ -1400,10 +1439,9 @@ asmlinkage int vprintk_emit(int facility, int level,
|
|
|
static char textbuf[LOG_LINE_MAX];
|
|
|
char *text = textbuf;
|
|
|
size_t text_len;
|
|
|
+ enum log_flags lflags = 0;
|
|
|
unsigned long flags;
|
|
|
int this_cpu;
|
|
|
- bool newline = false;
|
|
|
- bool prefix = false;
|
|
|
int printed_len = 0;
|
|
|
|
|
|
boot_delay_msec();
|
|
@@ -1442,7 +1480,7 @@ asmlinkage int vprintk_emit(int facility, int level,
|
|
|
recursion_bug = 0;
|
|
|
printed_len += strlen(recursion_msg);
|
|
|
/* emit KERN_CRIT message */
|
|
|
- log_store(0, 2, LOG_DEFAULT, 0,
|
|
|
+ log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
|
|
|
NULL, 0, recursion_msg, printed_len);
|
|
|
}
|
|
|
|
|
@@ -1455,7 +1493,7 @@ asmlinkage int vprintk_emit(int facility, int level,
|
|
|
/* mark and strip a trailing newline */
|
|
|
if (text_len && text[text_len-1] == '\n') {
|
|
|
text_len--;
|
|
|
- newline = true;
|
|
|
+ lflags |= LOG_NEWLINE;
|
|
|
}
|
|
|
|
|
|
/* strip syslog prefix and extract log level or control flags */
|
|
@@ -1465,7 +1503,7 @@ asmlinkage int vprintk_emit(int facility, int level,
|
|
|
if (level == -1)
|
|
|
level = text[1] - '0';
|
|
|
case 'd': /* KERN_DEFAULT */
|
|
|
- prefix = true;
|
|
|
+ lflags |= LOG_PREFIX;
|
|
|
case 'c': /* KERN_CONT */
|
|
|
text += 3;
|
|
|
text_len -= 3;
|
|
@@ -1475,22 +1513,20 @@ asmlinkage int vprintk_emit(int facility, int level,
|
|
|
if (level == -1)
|
|
|
level = default_message_loglevel;
|
|
|
|
|
|
- if (dict) {
|
|
|
- prefix = true;
|
|
|
- newline = true;
|
|
|
- }
|
|
|
+ if (dict)
|
|
|
+ lflags |= LOG_PREFIX|LOG_NEWLINE;
|
|
|
|
|
|
- if (!newline) {
|
|
|
+ if (!(lflags & LOG_NEWLINE)) {
|
|
|
/*
|
|
|
* Flush the conflicting buffer. An earlier newline was missing,
|
|
|
* or another task also prints continuation lines.
|
|
|
*/
|
|
|
- if (cont.len && (prefix || cont.owner != current))
|
|
|
+ if (cont.len && (lflags & LOG_PREFIX || cont.owner != current))
|
|
|
cont_flush();
|
|
|
|
|
|
/* buffer line if possible, otherwise store it right away */
|
|
|
if (!cont_add(facility, level, text, text_len))
|
|
|
- log_store(facility, level, LOG_DEFAULT, 0,
|
|
|
+ log_store(facility, level, lflags | LOG_CONT, 0,
|
|
|
dict, dictlen, text, text_len);
|
|
|
} else {
|
|
|
bool stored = false;
|
|
@@ -1502,13 +1538,13 @@ asmlinkage int vprintk_emit(int facility, int level,
|
|
|
* flush it out and store this line separately.
|
|
|
*/
|
|
|
if (cont.len && cont.owner == current) {
|
|
|
- if (!prefix)
|
|
|
+ if (!(lflags & LOG_PREFIX))
|
|
|
stored = cont_add(facility, level, text, text_len);
|
|
|
cont_flush();
|
|
|
}
|
|
|
|
|
|
if (!stored)
|
|
|
- log_store(facility, level, LOG_DEFAULT, 0,
|
|
|
+ log_store(facility, level, lflags, 0,
|
|
|
dict, dictlen, text, text_len);
|
|
|
}
|
|
|
printed_len += text_len;
|
|
@@ -1607,8 +1643,8 @@ static struct cont {
|
|
|
static struct log *log_from_idx(u32 idx) { return NULL; }
|
|
|
static u32 log_next(u32 idx) { return 0; }
|
|
|
static void call_console_drivers(int level, const char *text, size_t len) {}
|
|
|
-static size_t msg_print_text(const struct log *msg, bool syslog,
|
|
|
- char *buf, size_t size) { return 0; }
|
|
|
+static size_t msg_print_text(const struct log *msg, enum log_flags prev,
|
|
|
+ bool syslog, char *buf, size_t size) { return 0; }
|
|
|
static size_t cont_print_text(char *text, size_t size) { return 0; }
|
|
|
|
|
|
#endif /* CONFIG_PRINTK */
|
|
@@ -1884,6 +1920,7 @@ void wake_up_klogd(void)
|
|
|
/* the next printk record to write to the console */
|
|
|
static u64 console_seq;
|
|
|
static u32 console_idx;
|
|
|
+static enum log_flags console_prev;
|
|
|
|
|
|
/**
|
|
|
* console_unlock - unlock the console system
|
|
@@ -1944,6 +1981,7 @@ again:
|
|
|
/* messages are gone, move to first one */
|
|
|
console_seq = log_first_seq;
|
|
|
console_idx = log_first_idx;
|
|
|
+ console_prev = 0;
|
|
|
}
|
|
|
skip:
|
|
|
if (console_seq == log_next_seq)
|
|
@@ -1957,14 +1995,21 @@ skip:
|
|
|
*/
|
|
|
console_idx = log_next(console_idx);
|
|
|
console_seq++;
|
|
|
+ /*
|
|
|
+ * We will get here again when we register a new
|
|
|
+ * CON_PRINTBUFFER console. Clear the flag so we
|
|
|
+ * will properly dump everything later.
|
|
|
+ */
|
|
|
+ msg->flags &= ~LOG_NOCONS;
|
|
|
goto skip;
|
|
|
}
|
|
|
|
|
|
level = msg->level;
|
|
|
- len = msg_print_text(msg, false, text, sizeof(text));
|
|
|
-
|
|
|
+ len = msg_print_text(msg, console_prev, false,
|
|
|
+ text, sizeof(text));
|
|
|
console_idx = log_next(console_idx);
|
|
|
console_seq++;
|
|
|
+ console_prev = msg->flags;
|
|
|
raw_spin_unlock(&logbuf_lock);
|
|
|
|
|
|
stop_critical_timings(); /* don't trace print latency */
|
|
@@ -2227,6 +2272,7 @@ void register_console(struct console *newcon)
|
|
|
raw_spin_lock_irqsave(&logbuf_lock, flags);
|
|
|
console_seq = syslog_seq;
|
|
|
console_idx = syslog_idx;
|
|
|
+ console_prev = syslog_prev;
|
|
|
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
|
|
|
/*
|
|
|
* We're about to replay the log buffer. Only do this to the
|
|
@@ -2520,8 +2566,7 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
|
|
|
}
|
|
|
|
|
|
msg = log_from_idx(dumper->cur_idx);
|
|
|
- l = msg_print_text(msg, syslog,
|
|
|
- line, size);
|
|
|
+ l = msg_print_text(msg, 0, syslog, line, size);
|
|
|
|
|
|
dumper->cur_idx = log_next(dumper->cur_idx);
|
|
|
dumper->cur_seq++;
|
|
@@ -2561,6 +2606,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
|
|
|
u32 idx;
|
|
|
u64 next_seq;
|
|
|
u32 next_idx;
|
|
|
+ enum log_flags prev;
|
|
|
size_t l = 0;
|
|
|
bool ret = false;
|
|
|
|
|
@@ -2583,23 +2629,27 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
|
|
|
/* calculate length of entire buffer */
|
|
|
seq = dumper->cur_seq;
|
|
|
idx = dumper->cur_idx;
|
|
|
+ prev = 0;
|
|
|
while (seq < dumper->next_seq) {
|
|
|
struct log *msg = log_from_idx(idx);
|
|
|
|
|
|
- l += msg_print_text(msg, true, NULL, 0);
|
|
|
+ l += msg_print_text(msg, prev, true, NULL, 0);
|
|
|
idx = log_next(idx);
|
|
|
seq++;
|
|
|
+ prev = msg->flags;
|
|
|
}
|
|
|
|
|
|
/* move first record forward until length fits into the buffer */
|
|
|
seq = dumper->cur_seq;
|
|
|
idx = dumper->cur_idx;
|
|
|
+ prev = 0;
|
|
|
while (l > size && seq < dumper->next_seq) {
|
|
|
struct log *msg = log_from_idx(idx);
|
|
|
|
|
|
- l -= msg_print_text(msg, true, NULL, 0);
|
|
|
+ l -= msg_print_text(msg, prev, true, NULL, 0);
|
|
|
idx = log_next(idx);
|
|
|
seq++;
|
|
|
+ prev = msg->flags;
|
|
|
}
|
|
|
|
|
|
/* last message in next interation */
|
|
@@ -2607,14 +2657,14 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
|
|
|
next_idx = idx;
|
|
|
|
|
|
l = 0;
|
|
|
+ prev = 0;
|
|
|
while (seq < dumper->next_seq) {
|
|
|
struct log *msg = log_from_idx(idx);
|
|
|
|
|
|
- l += msg_print_text(msg, syslog,
|
|
|
- buf + l, size - l);
|
|
|
-
|
|
|
+ l += msg_print_text(msg, prev, syslog, buf + l, size - l);
|
|
|
idx = log_next(idx);
|
|
|
seq++;
|
|
|
+ prev = msg->flags;
|
|
|
}
|
|
|
|
|
|
dumper->next_seq = next_seq;
|