forked from luck/tmp_suning_uos_patched
printk: reimplement log_cont using record extension
Use the record extending feature of the ringbuffer to implement continuous messages. This preserves the existing continuous message behavior. Signed-off-by: John Ogness <john.ogness@linutronix.de> Reviewed-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Petr Mladek <pmladek@suse.com> Link: https://lore.kernel.org/r/20200914123354.832-7-john.ogness@linutronix.de
This commit is contained in:
parent
4cfc7258f8
commit
f5f022e53b
|
@ -535,7 +535,10 @@ static int log_store(u32 caller_id, int facility, int level,
|
||||||
r.info->caller_id = caller_id;
|
r.info->caller_id = caller_id;
|
||||||
|
|
||||||
/* insert message */
|
/* insert message */
|
||||||
prb_commit(&e);
|
if ((flags & LOG_CONT) || !(flags & LOG_NEWLINE))
|
||||||
|
prb_commit(&e);
|
||||||
|
else
|
||||||
|
prb_final_commit(&e);
|
||||||
|
|
||||||
return (text_len + trunc_msg_len);
|
return (text_len + trunc_msg_len);
|
||||||
}
|
}
|
||||||
|
@ -1084,7 +1087,7 @@ static unsigned int __init add_to_rb(struct printk_ringbuffer *rb,
|
||||||
dest_r.info->ts_nsec = r->info->ts_nsec;
|
dest_r.info->ts_nsec = r->info->ts_nsec;
|
||||||
dest_r.info->caller_id = r->info->caller_id;
|
dest_r.info->caller_id = r->info->caller_id;
|
||||||
|
|
||||||
prb_commit(&e);
|
prb_final_commit(&e);
|
||||||
|
|
||||||
return prb_record_text_space(&e);
|
return prb_record_text_space(&e);
|
||||||
}
|
}
|
||||||
|
@ -1884,87 +1887,26 @@ static inline u32 printk_caller_id(void)
|
||||||
0x80000000 + raw_smp_processor_id();
|
0x80000000 + raw_smp_processor_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Continuation lines are buffered, and not committed to the record buffer
|
|
||||||
* until the line is complete, or a race forces it. The line fragments
|
|
||||||
* though, are printed immediately to the consoles to ensure everything has
|
|
||||||
* reached the console in case of a kernel crash.
|
|
||||||
*/
|
|
||||||
static struct cont {
|
|
||||||
char buf[LOG_LINE_MAX];
|
|
||||||
size_t len; /* length == 0 means unused buffer */
|
|
||||||
u32 caller_id; /* printk_caller_id() of first print */
|
|
||||||
u64 ts_nsec; /* time of first print */
|
|
||||||
u8 level; /* log level of first message */
|
|
||||||
u8 facility; /* log facility of first message */
|
|
||||||
enum log_flags flags; /* prefix, newline flags */
|
|
||||||
} cont;
|
|
||||||
|
|
||||||
static void cont_flush(void)
|
|
||||||
{
|
|
||||||
if (cont.len == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
log_store(cont.caller_id, cont.facility, cont.level, cont.flags,
|
|
||||||
cont.ts_nsec, NULL, 0, cont.buf, cont.len);
|
|
||||||
cont.len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool cont_add(u32 caller_id, int facility, int level,
|
|
||||||
enum log_flags flags, const char *text, size_t len)
|
|
||||||
{
|
|
||||||
/* If the line gets too long, split it up in separate records. */
|
|
||||||
if (cont.len + len > sizeof(cont.buf)) {
|
|
||||||
cont_flush();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cont.len) {
|
|
||||||
cont.facility = facility;
|
|
||||||
cont.level = level;
|
|
||||||
cont.caller_id = caller_id;
|
|
||||||
cont.ts_nsec = local_clock();
|
|
||||||
cont.flags = flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(cont.buf + cont.len, text, len);
|
|
||||||
cont.len += len;
|
|
||||||
|
|
||||||
// The original flags come from the first line,
|
|
||||||
// but later continuations can add a newline.
|
|
||||||
if (flags & LOG_NEWLINE) {
|
|
||||||
cont.flags |= LOG_NEWLINE;
|
|
||||||
cont_flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t log_output(int facility, int level, enum log_flags lflags, const char *dict, size_t dictlen, char *text, size_t text_len)
|
static size_t log_output(int facility, int level, enum log_flags lflags, const char *dict, size_t dictlen, char *text, size_t text_len)
|
||||||
{
|
{
|
||||||
const u32 caller_id = printk_caller_id();
|
const u32 caller_id = printk_caller_id();
|
||||||
|
|
||||||
/*
|
if (lflags & LOG_CONT) {
|
||||||
* If an earlier line was buffered, and we're a continuation
|
struct prb_reserved_entry e;
|
||||||
* write from the same context, try to add it to the buffer.
|
struct printk_record r;
|
||||||
*/
|
|
||||||
if (cont.len) {
|
|
||||||
if (cont.caller_id == caller_id && (lflags & LOG_CONT)) {
|
|
||||||
if (cont_add(caller_id, facility, level, lflags, text, text_len))
|
|
||||||
return text_len;
|
|
||||||
}
|
|
||||||
/* Otherwise, make sure it's flushed */
|
|
||||||
cont_flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Skip empty continuation lines that couldn't be added - they just flush */
|
prb_rec_init_wr(&r, text_len, 0);
|
||||||
if (!text_len && (lflags & LOG_CONT))
|
if (prb_reserve_in_last(&e, prb, &r, caller_id)) {
|
||||||
return 0;
|
memcpy(&r.text_buf[r.info->text_len], text, text_len);
|
||||||
|
r.info->text_len += text_len;
|
||||||
/* If it doesn't end in a newline, try to buffer the current line */
|
if (lflags & LOG_NEWLINE) {
|
||||||
if (!(lflags & LOG_NEWLINE)) {
|
r.info->flags |= LOG_NEWLINE;
|
||||||
if (cont_add(caller_id, facility, level, lflags, text, text_len))
|
prb_final_commit(&e);
|
||||||
|
} else {
|
||||||
|
prb_commit(&e);
|
||||||
|
}
|
||||||
return text_len;
|
return text_len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store it in the record log */
|
/* Store it in the record log */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user