diff options
author | Alex Elder <elder@linaro.org> | 2014-07-17 12:41:05 -0500 |
---|---|---|
committer | Alex Elder <elder@linaro.org> | 2014-07-22 08:52:10 -0500 |
commit | 8a9d4d390d1bd5c16962749d486bacba7bbef7a6 (patch) | |
tree | c0cfcd4821f0115cb488d60d72fdab066d3869dc | |
parent | ecff1f82613cd9e1d75089b6c37e818f4c5d2b74 (diff) |
printk: improve some commentary; tidy upreview/more-printk-flags-v2
Add some comments to explain how the log flags are used to control
how records get formatted. Also add and refine some comments in
vprintk_emit().
Now that we're done fixing up log record flags, simplify how they're
used in computing some local variable values in msg_print_text().
Use a local variable "flush_cont" in vprintk_emit() to factor out a
common expression used later in that function.
Signed-off-by: Alex Elder <elder@linaro.org>
-rw-r--r-- | kernel/printk/printk.c | 63 |
1 files changed, 41 insertions, 22 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 49c92382bc3..cecdc1bfaed 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -141,6 +141,12 @@ EXPORT_SYMBOL(console_set_on_cmdline); static int console_may_schedule; /* + * Each call to printk() fills a record in a circular log buffer. + * The contents of the log buffer are read by various subsystems + * (including the console subsystem), each of which formats the + * content of log buffers for human consumption. Flags in each + * log record are used to track formatting-related state. + * * The printk log buffer consists of a chain of concatenated variable * length records. Every record starts with a record header, containing * the overall length of the record. @@ -150,7 +156,7 @@ static int console_may_schedule; * are stored.. * * If the heads indicate available messages, the length in the header - * tells the start next message. A length == 0 for the next message + * tells the start of the next message. A length == 0 for the next message * indicates a wrap-around to the beginning of the buffer. * * Every record carries the monotonic timestamp in microseconds, as well as @@ -192,6 +198,16 @@ static int console_may_schedule; * 67 "g" * 0032 00 00 00 padding to next message header * + * If a printk() call contains no newline, its content is saved in a + * special "cont" buffer rather than being written directly into the + * log. One or more follow-in printk() calls from the same source + * can then be combined into a single newline-terminated message (if + * possible) before the combined result is saved into a log record. + * Occasionally a buffered/partial message needs to be flushed to + * the log before the logically next printk() call is seen. When + * this occurs, the incomplete record (with no LOG_NEWLINE) will + * be followed by a new record marked LOG_PREFIX. + * * The 'struct printk_log' buffer header must never be directly exported to * userspace, it is a kernel-private implementation detail that might * need to be changed in the future, when the requirements change. @@ -1005,17 +1021,14 @@ static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev, { const char *text = log_text(msg); size_t text_size = msg->text_len; - bool prefix = true; - bool newline = true; size_t len = 0; + bool prefix; + bool newline; - if (!(prev & LOG_NEWLINE) && !(msg->flags & LOG_PREFIX)) - prefix = false; - - if (!(msg->flags & LOG_NEWLINE)) - newline = false; - - if (!(prev & LOG_NEWLINE) && (msg->flags & LOG_PREFIX) && len < size) { + prefix = (prev & LOG_NEWLINE) || (msg->flags & LOG_PREFIX); + newline = !!(msg->flags & LOG_NEWLINE); + /* Insert a newline if we're terminating the previous line early */ + if (prefix && !(prev & LOG_NEWLINE) && len < size) { if (buf) buf[len++] = '\n'; else @@ -1600,6 +1613,7 @@ asmlinkage int vprintk_emit(int facility, int level, int this_cpu; int printed_len = 0; bool in_sched = false; + bool flush_cont = false; /* cpu currently holding logbuf_lock in this function */ static volatile unsigned int logbuf_cpu = UINT_MAX; @@ -1698,12 +1712,16 @@ asmlinkage int vprintk_emit(int facility, int level, if (dict) lflags = LOG_PREFIX|LOG_NEWLINE; + /* + * If the previous printk() call had no newline, it will be buffered. + * If the buffered message was produced by someone else, or if this + * call is forcing a new record, we will need to flush the buffer + * rather than merge this message into it. + */ + flush_cont = (cont.owner != current) || (lflags & LOG_PREFIX); 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)) + /* If the buffered record conflicts, flush it first. */ + if (cont.len && flush_cont) cont_flush(LOG_NEWLINE); /* buffer line if possible, otherwise store it right away */ @@ -1716,20 +1734,21 @@ asmlinkage int vprintk_emit(int facility, int level, 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 there's a buffered message, try to merge with + * it, then flush whatever's buffered to the log. */ if (cont.len) { - if (cont.owner == current && !(lflags & LOG_PREFIX)) + if (!flush_cont) stored = cont_add(facility, level, text, text_len); cont_flush(LOG_NEWLINE); } + /* + * Record how much we just formatted. If cont_add() didn't + * combine this message with the buffered one we still have + * to store this one to the log. + */ if (stored) printed_len += text_len; else |