[PATCH v2 10/14] printk: track previously logged message in log_store()
From: Jan H. SchÃnherr
Date: Thu Dec 06 2012 - 12:10:27 EST
Centrally track information about the previous message in log_store().
This knowledge allows us to decide immediately whether the current
message is a continuation of the previous message. And if that is so, to
keep the correct log level (continuation records do not have a log level).
Later, this will also allow us to remove the tracking of the previous
message flags throughout the syslog/kmsg formatting code.
Signed-off-by: Jan H. SchÃnherr <schnhrr@xxxxxxxxxxxxxxx>
---
v2:
- Fixed a bug that could mismerge continuation records, because
log_store() used "current" as the owner of the message passed in,
which might be incorrect when used from cont_flush().
- refactored code
- refactored patches
---
kernel/printk.c | 47 ++++++++++++++++++++++++++++++++++++-----------
1 file changed, 36 insertions(+), 11 deletions(-)
diff --git a/kernel/printk.c b/kernel/printk.c
index 52ccf93..151c77a 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -226,6 +226,10 @@ static size_t syslog_partial;
static u64 log_first_seq;
static u32 log_first_idx;
+/* information about the last stored message */
+static struct log *log_last_msg;
+static struct task_struct *log_last_owner;
+
/* index and sequence number of the next record to store in the buffer */
static u64 log_next_seq;
static u32 log_next_idx;
@@ -300,18 +304,36 @@ static u32 log_next(u32 idx)
return idx + msg->len;
}
+/* return correct level for continuation records */
+static int log_infer_level(struct task_struct *owner, int facility, int level,
+ enum log_flags flags)
+{
+ if (flags & LOG_PREFIX || level != -1 || !log_last_msg ||
+ log_last_msg->facility != facility || log_last_owner != owner ||
+ log_last_msg->flags & LOG_NEWLINE)
+ return level;
+ return log_last_msg->level;
+}
+
/* insert record into the buffer, discard old ones, update heads */
-static void log_store(int facility, int level,
+static void log_store(struct task_struct *owner, int facility, int level,
enum log_flags flags, u64 ts_nsec,
const char *dict, u16 dict_len,
const char *text, u16 text_len)
{
struct log *msg;
u32 size, pad_len;
-
- /* store something meaningful, when no loglevel was given */
- if (level == -1)
- level = default_message_loglevel;
+ int inferred_level;
+
+ /* setup flags/level for storage */
+ inferred_level = log_infer_level(owner, facility, -1, flags);
+ if (inferred_level == -1) {
+ flags |= LOG_PREFIX;
+ if (level == -1)
+ level = default_message_loglevel;
+ } else {
+ level = inferred_level;
+ }
/* number of '\0' padding bytes to next message */
size = sizeof(struct log) + text_len + dict_len;
@@ -329,7 +351,7 @@ static void log_store(int facility, int level,
if (free > size + sizeof(struct log))
break;
- /* drop old messages until we have enough contiuous space */
+ /* drop old messages until we have enough continuous space */
log_first_idx = log_next(log_first_idx);
log_first_seq++;
}
@@ -363,6 +385,9 @@ static void log_store(int facility, int level,
/* insert message */
log_next_idx += msg->len;
log_next_seq++;
+
+ log_last_owner = owner;
+ log_last_msg = msg;
}
/* /dev/kmsg - userspace message inject/listen interface */
@@ -1432,8 +1457,8 @@ static void cont_flush(void)
if (cont.cons)
cont.flags |= LOG_NOCONS;
- log_store(cont.facility, cont.level, cont.flags, cont.ts_nsec, NULL, 0,
- cont.buf, cont.len);
+ log_store(cont.owner, cont.facility, cont.level, cont.flags,
+ cont.ts_nsec, NULL, 0, cont.buf, cont.len);
/*
* If no fragment of this line ever reached the console or everything
@@ -1550,7 +1575,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_PREFIX|LOG_NEWLINE, 0,
+ log_store(current, 0, 2, LOG_PREFIX | LOG_NEWLINE, 0,
NULL, 0, recursion_msg, printed_len);
}
@@ -1607,7 +1632,7 @@ asmlinkage int vprintk_emit(int facility, int level,
/* buffer line if possible, otherwise store it right away */
if (!cont_add(facility, level, lflags, text, text_len))
- log_store(facility, level, lflags, 0,
+ log_store(current, facility, level, lflags, 0,
dict, dictlen, text, text_len);
} else {
bool stored = false;
@@ -1626,7 +1651,7 @@ asmlinkage int vprintk_emit(int facility, int level,
}
if (!stored)
- log_store(facility, level, lflags, 0,
+ log_store(current, facility, level, lflags, 0,
dict, dictlen, text, text_len);
}
printed_len += text_len;
--
1.8.0.1.20.g7c65b2e.dirty
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/