On Mon, Jan 27, 2014 at 11:48 AM, Luck, Tony <tony.luck@xxxxxxxxx> wrote: >> The thing is, unless the next printk is a continuation (PR_CONT), the >> newline should be added at that point. And if it isn't, then that's a >> bug. So I'm wondering how this issue got noticed - does it actually >> cause user-visible issues, or was it just code reading? > > The next thing that happened was a debug printk() that didn't have > any log level specified. > > printk("CMCI on cpu%d\n", smp_processor_id()); > > and no newline was added. Ok, I think that's a bug. Only an explicit KERN_CONT prefix should cause a line continuation. The new msg code seems to be terminally confused about this, and for example, seems to completely ignore the KERN_CONT flag, and instead tests for just LOG_PREFIX (which is set for any prefix, not the KERN_CONT 'c' prefix). And then it turns LOG_CONT to be about the *current* printk missing a newline. So the whole new msg code seems to be really confused about what the whole KERN_CONT thing was all about, and mixed it up with whether the message ended in a newline or not, which is entirely bogus. Adding more people. Looking at the code in vprintk_emit(), somebody is really confused. Anyway, attached is a *totally* untested patch. Comments? Linus
kernel/printk/printk.c | 43 ++++++++++++------------------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index b1d255f04135..fae5c8ab607d 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1561,7 +1561,9 @@ asmlinkage int vprintk_emit(int facility, int level, level = kern_level - '0'; case 'd': /* KERN_DEFAULT */ lflags |= LOG_PREFIX; + break; case 'c': /* KERN_CONT */ + lflags |= LOG_CONT; break; } text_len -= end_of_header - text; @@ -1575,40 +1577,19 @@ asmlinkage int vprintk_emit(int facility, int level, if (dict) lflags |= LOG_PREFIX|LOG_NEWLINE; - if (!(lflags & LOG_NEWLINE)) { - /* - * Flush the conflicting buffer. An earlier newline was missing, - * or another task also prints continuation lines. - */ - if (cont.len && (lflags & LOG_PREFIX || cont.owner != current)) - cont_flush(LOG_NEWLINE); - - /* buffer line if possible, otherwise store it right away */ - if (!cont_add(facility, level, text, text_len)) - log_store(facility, level, lflags | LOG_CONT, 0, - dict, dictlen, text, text_len); - } else { - bool stored = false; - - /* - * If an earlier newline was missing and it was the same task, - * either merge it with the current buffer and flush, or if - * there was a race with interrupts (prefix == true) then just - * flush it out and store this line separately. - * If the preceding printk was from a different task and missed - * a newline, flush and append the newline. - */ - if (cont.len) { - if (cont.owner == current && !(lflags & LOG_PREFIX)) - stored = cont_add(facility, level, text, - text_len); + if (cont.len) { + if (cont.owner != current || !(lflags & LOG_CONT)) { cont_flush(LOG_NEWLINE); + lflags &= ~LOG_CONT; } - - if (!stored) - log_store(facility, level, lflags, 0, - dict, dictlen, text, text_len); } + + /* + * If LOG_CONT is set, try to add the new message to any old one. + * If that fails - or LOG_CONT wasmn't set - create a new record. + */ + if (!(lflags & LOG_CONT) || !cont_add(facility, level, text, text_len)) + log_store(facility, level, lflags, 0, dict, dictlen, text, text_len); printed_len += text_len; /*