[PATCH 3/6] nvram: Always capture start of oops report to NVRAM
Jim Keniston
jkenisto at us.ibm.com
Sun Nov 14 15:15:27 EST 2010
If we don't have room to capture the entire oops report, capture as much
as possible, starting 150 chars before the "Oops:" line.
Signed-off-by: Jim Keniston <jkenisto at us.ibm.com>
---
arch/powerpc/platforms/pseries/nvram.c | 91 ++++++++++++++++++++++++++++++++
1 files changed, 91 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 6c88cda..e1bc1a4 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -446,6 +446,87 @@ static size_t capture_last_msgs(const char *old_msgs, size_t old_len,
}
}
+/* Find the last occurrence of needle in haystack, which is haystack_len long.*/
+static const char *strnrstr(const char *haystack, const char *needle,
+ size_t haystack_len)
+{
+ size_t needle_len = strlen(needle);
+ const char *haystack_end = haystack + haystack_len;
+ const char *prev, *next = NULL;
+ do {
+ prev = next;
+ next = strnstr(haystack, needle, haystack_len);
+ if (next) {
+ haystack = next + needle_len;
+ haystack_len = haystack_end - haystack;
+ }
+ } while (next);
+ return prev;
+}
+
+/* The preamble is the last bit of messages logged before the oops. */
+#define PREAMBLE_CHARS 150
+#define OOPS_TAG "Oops: "
+
+/*
+ * Find the beginning of the most recent oops report, back up PREAMBLE_CHARS
+ * characters, and copy up to captured_len characters from there to captured[].
+ * If we can't find the oops, just capture the end of the printk buffer,
+ * if we haven't already.
+ */
+static size_t capture_oops(const char *old_msgs, size_t old_len,
+ const char *new_msgs, size_t new_len,
+ char *captured, size_t capture_len,
+ size_t already_captured)
+{
+ const char *poops; /* Points to the 'O' in "Oops: ..." */
+ const char *preamble;
+ const char *old_end = old_msgs + old_len;
+ const char *new_end = new_msgs + new_len;
+ size_t nc1, nc2;
+
+ if ((poops = strnrstr(new_msgs, OOPS_TAG, new_len)) != NULL) {
+ /* Oops starts in new_msgs -- the most common case. */
+ preamble = poops - PREAMBLE_CHARS;
+ if (preamble >= new_msgs) {
+ /* preamble is also in new_msgs. */
+ nc1 = min(capture_len, (size_t)(new_end - preamble));
+ memcpy(captured, preamble, nc1);
+ nc2 = 0;
+ } else {
+ /* Have to get some of the preamble from old_msgs */
+ nc1 = min((size_t)(new_msgs - preamble), old_len);
+ memcpy(captured, (old_end - nc1), nc1);
+ nc2 = min(new_len, capture_len - nc1);
+ memcpy(captured + nc1, new_msgs, nc2);
+ }
+ } else if ((poops = strnrstr(old_msgs, OOPS_TAG, old_len)) != NULL) {
+ /* Oops starts in old_msgs. */
+ preamble = poops - PREAMBLE_CHARS;
+ if (preamble < old_msgs)
+ preamble = old_msgs;
+ nc1 = min(capture_len, (size_t)(old_end - preamble));
+ memcpy(captured, preamble, nc1);
+ nc2 = min((size_t)(capture_len - nc1), new_len);
+ memcpy(captured + nc1, new_msgs, nc2);
+ } else {
+ /*
+ * Either there was a VERY long oops report that scrolled
+ * out of the printk buffer, or the "Oops" tag is split
+ * across old_msgs and new_msgs, or oopses don't start with
+ * "Oops" anymore. Just capture as much of the last messages
+ * as we think we can squeeze into NVRAM.
+ */
+ if (already_captured)
+ return already_captured;
+ nc1 = capture_last_msgs(old_msgs, old_len, new_msgs,
+ new_len, captured, capture_len);
+ nc2 = 0;
+ }
+
+ return nc1 + nc2;
+}
+
/* our kmsg_dump callback */
static void oops_to_nvram(struct kmsg_dumper *dumper,
enum kmsg_dump_reason reason,
@@ -457,6 +538,16 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
text_len = capture_last_msgs(old_msgs, old_len, new_msgs, new_len,
oops_buf, oops_buf_sz);
+ if (reason == KMSG_DUMP_OOPS) {
+ /*
+ * Ensure that we have the start of the oops report,
+ * and the message(s) leading up to it.
+ */
+ const char *poops = strnrstr(oops_buf, OOPS_TAG, oops_buf_sz);
+ if (!poops || poops < oops_buf + PREAMBLE_CHARS)
+ text_len = capture_oops(old_msgs, old_len, new_msgs,
+ new_len, oops_buf, oops_buf_sz, text_len);
+ }
(void) nvram_write_os_partition(&oops_log_partition, oops_buf,
(int) text_len, ERR_TYPE_KERNEL_PANIC, ++oops_count);
}
More information about the Linuxppc-dev
mailing list