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 <jkeni...@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); } _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev