[PATCH 1/2] printk: Add dictionary information in structure cont

Yoshihiro YUNOMAE
2013-12-20T09:41:45Z

Add dictionary information in structure cont.
Dictionary information is added when a driver uses structured printk, and the
information is shown in /dev/kmsg. Current kernel directly stores the
information to log_buf. This patch stores the dict information in structure cont
first, then the information in cont is stored to log_buf.

Signed-off-by: Yoshihiro YUNOMAE <yoshihiro.yunomae.ez@hitachi.com>
Cc: Kay Sievers <kay@vrfy.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Joe Perches <joe@perches.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: linux-kernel@vger.kernel.org
---
kernel/printk/printk.c | 70 ++++++++++++++++++++++++++++++++----------------
1 file changed, 47 insertions(+), 23 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index be7c86b..c3662e6 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1391,8 +1391,10 @@ static inline void printk_delay(void)
* 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 */
+ char text[LOG_LINE_MAX];
+ size_t text_len; /* length == 0 means unused buffer */
+ char dict[LOG_LINE_MAX]; /* stores dict */
+ size_t dict_len; /* 0 means dict is unstored */
size_t cons; /* bytes written to console */
struct task_struct *owner; /* task of first print*/
u64 ts_nsec; /* time of first print */
@@ -1406,7 +1408,7 @@ static void cont_flush(enum log_flags flags)
{
if (cont.flushed)
return;
- if (cont.len == 0)
+ if (cont.text_len == 0)
return;

if (cont.cons) {
@@ -1416,7 +1418,7 @@ static void cont_flush(enum log_flags flags)
* line. LOG_NOCONS suppresses a duplicated output.
*/
log_store(cont.facility, cont.level, flags | LOG_NOCONS,
- cont.ts_nsec, NULL, 0, cont.buf, cont.len);
+ cont.ts_nsec, NULL, 0, cont.text, cont.text_len);
cont.flags = flags;
cont.flushed = true;
} else {
@@ -1425,23 +1427,32 @@ static void cont_flush(enum log_flags flags)
* just submit it to the store and free the buffer.
*/
log_store(cont.facility, cont.level, flags, 0,
- NULL, 0, cont.buf, cont.len);
- cont.len = 0;
+ NULL, 0, cont.text, cont.text_len);
+ cont.text_len = 0;
}
}

-static bool cont_add(int facility, int level, const char *text, size_t len)
+static void cont_dict_add(const char *dict, size_t dict_len)
{
- if (cont.len && cont.flushed)
+ if (cont.dict_len + dict_len > sizeof(cont.dict))
+ return;
+
+ memcpy(cont.dict + cont.dict_len, dict, dict_len);
+ cont.dict_len += dict_len;
+}
+
+static bool cont_add(int facility, int level, const char *text, size_t text_len)
+{
+ if (cont.text_len && cont.flushed)
return false;

- if (cont.len + len > sizeof(cont.buf)) {
+ if (cont.text_len + text_len > sizeof(cont.text)) {
/* the line gets too long, split it up in separate records */
cont_flush(LOG_CONT);
return false;
}

- if (!cont.len) {
+ if (!cont.text_len) {
cont.facility = facility;
cont.level = level;
cont.owner = current;
@@ -1451,10 +1462,10 @@ static bool cont_add(int facility, int level, const char *text, size_t len)
cont.flushed = false;
}

- memcpy(cont.buf + cont.len, text, len);
- cont.len += len;
+ memcpy(cont.text + cont.text_len, text, text_len);
+ cont.text_len += text_len;

- if (cont.len > (sizeof(cont.buf) * 80) / 100)
+ if (cont.text_len > (sizeof(cont.text) * 80) / 100)
cont_flush(LOG_CONT);

return true;
@@ -1470,20 +1481,20 @@ static size_t cont_print_text(char *text, size_t size)
size -= textlen;
}

- len = cont.len - cont.cons;
+ len = cont.text_len - cont.cons;
if (len > 0) {
if (len+1 > size)
len = size-1;
- memcpy(text + textlen, cont.buf + cont.cons, len);
+ memcpy(text + textlen, cont.text + cont.cons, len);
textlen += len;
- cont.cons = cont.len;
+ cont.cons = cont.text_len;
}

if (cont.flushed) {
if (cont.flags & LOG_NEWLINE)
text[textlen++] = '\n';
/* got everything, release buffer */
- cont.len = 0;
+ cont.text_len = 0;
}
return textlen;
}
@@ -1576,21 +1587,29 @@ asmlinkage int vprintk_emit(int facility, int level,
if (level == -1)
level = default_message_loglevel;

- if (dict)
+ if (dict) {
lflags |= LOG_PREFIX|LOG_NEWLINE;

+ /* Another task is trying to output a message */
+ if (cont.text_len && cont.owner != current)
+ cont_flush(LOG_NEWLINE);
+
+ cont_dict_add(dict, dictlen);
+ }
+
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 (cont.text_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);
+ NULL, 0, text, text_len);
} else {
bool stored = false;

@@ -1600,7 +1619,7 @@ asmlinkage int vprintk_emit(int facility, int level,
* there was a race with interrupts (prefix == true) then just
* flush it out and store this line separately.
*/
- if (cont.len && cont.owner == current) {
+ if (cont.text_len && cont.owner == current) {
if (!(lflags & LOG_PREFIX))
stored = cont_add(facility, level, text, text_len);
cont_flush(LOG_NEWLINE);
@@ -1608,7 +1627,12 @@ asmlinkage int vprintk_emit(int facility, int level,

if (!stored)
log_store(facility, level, lflags, 0,
- dict, dictlen, text, text_len);
+ cont.dict, cont.dict_len, text, text_len);
+ /*
+ * Structured printk always starts a new line now, so clear
+ * current dictionary information for next structured printk.
+ */
+ cont.dict_len = 0;
}
printed_len += text_len;

@@ -1974,7 +1998,7 @@ static void console_cont_flush(char *text, size_t size)

raw_spin_lock_irqsave(&logbuf_lock, flags);

- if (!cont.len)
+ if (!cont.text_len)
goto out;

/*