diff options
author | Kay Sievers <kay@vrfy.org> | 2012-05-30 13:21:23 +0200 |
---|---|---|
committer | Kay Sievers <kay@vrfy.org> | 2012-05-30 13:21:23 +0200 |
commit | 87194496259865729be1fccde58309002ce851c0 (patch) | |
tree | 16fd4795a53b70668754dbbd5e4f1c89536772c5 | |
parent | 607b6e8fa7ca61dd385d632fe51c6afc5f5374b7 (diff) | |
download | patches-87194496259865729be1fccde58309002ce851c0.tar.gz |
update
-rw-r--r-- | kmsg_dump.patch | 168 |
1 files changed, 114 insertions, 54 deletions
diff --git a/kmsg_dump.patch b/kmsg_dump.patch index f3ee532..e706dca 100644 --- a/kmsg_dump.patch +++ b/kmsg_dump.patch @@ -1,11 +1,11 @@ --- - arch/powerpc/platforms/pseries/nvram.c | 60 +--------- - arch/x86/platform/mrst/early_printk_mrst.c | 13 -- - drivers/mtd/mtdoops.c | 22 --- - fs/pstore/platform.c | 34 ++--- - include/linux/kmsg_dump.h | 39 +++++- - kernel/printk.c | 173 ++++++++++++++++++++++++----- - 6 files changed, 204 insertions(+), 137 deletions(-) + arch/powerpc/platforms/pseries/nvram.c | 61 ------- + arch/x86/platform/mrst/early_printk_mrst.c | 13 - + drivers/mtd/mtdoops.c | 22 -- + fs/pstore/platform.c | 34 +--- + include/linux/kmsg_dump.h | 45 ++++- + kernel/printk.c | 222 +++++++++++++++++++++++++---- + 6 files changed, 259 insertions(+), 138 deletions(-) --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -88,7 +88,7 @@ { static unsigned int oops_count = 0; static bool panicking = false; -@@ -660,14 +613,13 @@ static void oops_to_nvram(struct kmsg_du +@@ -660,14 +613,14 @@ static void oops_to_nvram(struct kmsg_du return; if (big_oops_buf) { @@ -102,6 +102,7 @@ if (rc != 0) { - text_len = capture_last_msgs(old_msgs, old_len, - new_msgs, new_len, oops_data, oops_data_sz); ++ kmsg_dump_rewind(dumper); + kmsg_dump_get_buffer(dumper, true, + oops_data, oops_data_sz, &text_len); err_type = ERR_TYPE_KERNEL_PANIC; @@ -256,7 +257,7 @@ KMSG_DUMP_PANIC, KMSG_DUMP_OOPS, KMSG_DUMP_EMERG, -@@ -31,23 +32,35 @@ enum kmsg_dump_reason { +@@ -31,23 +32,37 @@ enum kmsg_dump_reason { /** * struct kmsg_dumper - kernel crash message dumper structure @@ -291,15 +292,17 @@ void kmsg_dump(enum kmsg_dump_reason reason); +bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, -+ char *line, size_t size, size_t *len); ++ char *line, size_t size, size_t *len); + +bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, + char *buf, size_t size, size_t *len); + ++void kmsg_dump_rewind(struct kmsg_dumper *dumper); ++ int kmsg_dump_register(struct kmsg_dumper *dumper); int kmsg_dump_unregister(struct kmsg_dumper *dumper); -@@ -56,6 +69,18 @@ static inline void kmsg_dump(enum kmsg_d +@@ -56,6 +71,22 @@ static inline void kmsg_dump(enum kmsg_d { } @@ -315,6 +318,10 @@ + return false; +} + ++void kmsg_dump_rewind(struct kmsg_dumper *dumper) ++{ ++} ++ static inline int kmsg_dump_register(struct kmsg_dumper *dumper) { return -EINVAL; @@ -347,7 +354,15 @@ next_seq = log_next_seq; len = 0; -@@ -2305,43 +2307,158 @@ module_param_named(always_kmsg_dump, alw +@@ -2300,48 +2302,210 @@ module_param_named(always_kmsg_dump, alw + * kmsg_dump - dump kernel log to kernel message dumpers. + * @reason: the reason (oops, panic etc) for dumping + * +- * Iterate through each of the dump devices and call the oops/panic +- * callbacks with the log buffer. ++ * Call each of the registered dumper's dump() callback, which can ++ * retrieve the kmsg records with kmsg_dump_get_line() or ++ * kmsg_dump_get_buffer(). */ void kmsg_dump(enum kmsg_dump_reason reason) { @@ -367,46 +382,42 @@ + list_for_each_entry_rcu(dumper, &dump_list, list) { + if (dumper->max_reason && reason > dumper->max_reason) + continue; - -- raw_spin_lock_irqsave(&logbuf_lock, flags); -- if (syslog_seq < log_first_seq) -- idx = syslog_idx; -- else -- idx = log_first_idx; -- -- if (idx > log_next_idx) { -- s1 = log_buf; -- l1 = log_next_idx; ++ + /* initialize iterator with data about the stored records */ + dumper->active = true; - -- s2 = log_buf + idx; -- l2 = log_buf_len - idx; -- } else { -- s1 = ""; -- l1 = 0; ++ + raw_spin_lock_irqsave(&logbuf_lock, flags); + dumper->cur_seq = clear_seq; + dumper->cur_idx = clear_idx; + dumper->next_seq = log_next_seq; + dumper->next_idx = log_next_idx; + raw_spin_unlock_irqrestore(&logbuf_lock, flags); - -- s2 = log_buf + idx; -- l2 = log_next_idx - idx; ++ + /* invoke dumper which will iterate over records */ + dumper->dump(dumper, reason); + + /* reset iterator */ + dumper->active = false; - } ++ } + rcu_read_unlock(); +} + -+/* -+ * Start at the *oldest* kmsg record, and print one line into the provided -+ * buffer. Repeated calls will return the next record. A return value of -+ * FALSE indicates that all records are read including the youngest one. ++/** ++ * kmsg_dump_get_line - retrieve one kmsg log line ++ * @dumper: registered kmsg dumper ++ * @syslog: include the "<4>" prefixes ++ * @line: buffer to copy the line to ++ * @size: maximum size of the buffer ++ * @len: length of line placed into buffer ++ * ++ * Start at the beginning of the kmsg buffer, with the oldest kmsg ++ * record, and copy one record into the provided buffer. ++ * ++ * Consecutive calls will return the next available record moving ++ * towards the end of the buffer with the youngest messages. ++ * ++ * A return value of FALSE indicate that there are no more records to ++ * read. + */ +bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, + char *line, size_t size, size_t *len) @@ -418,20 +429,35 @@ + + if (!dumper->active) + goto out; -+ -+ raw_spin_lock_irqsave(&logbuf_lock, flags); + + raw_spin_lock_irqsave(&logbuf_lock, flags); +- if (syslog_seq < log_first_seq) +- idx = syslog_idx; +- else +- idx = log_first_idx; +- +- if (idx > log_next_idx) { +- s1 = log_buf; +- l1 = log_next_idx; + if (dumper->cur_seq < log_first_seq) { + /* messages are gone, move to first available one */ + dumper->cur_seq = log_first_seq; + dumper->cur_idx = log_first_idx; + } -+ + +- s2 = log_buf + idx; +- l2 = log_buf_len - idx; +- } else { +- s1 = ""; +- l1 = 0; + /* last entry */ + if (dumper->cur_seq >= log_next_seq) { + raw_spin_unlock_irqrestore(&logbuf_lock, flags); + goto out; + } -+ + +- s2 = log_buf + idx; +- l2 = log_next_idx - idx; + msg = log_from_idx(dumper->cur_idx); + l = msg_print_text(msg, syslog, + line, size); @@ -439,23 +465,32 @@ + dumper->cur_idx = log_next(dumper->cur_idx); + dumper->cur_seq++; + ret = true; - raw_spin_unlock_irqrestore(&logbuf_lock, flags); ++ raw_spin_unlock_irqrestore(&logbuf_lock, flags); +out: + if (len) + *len = l; + return ret; +} +EXPORT_SYMBOL_GPL(kmsg_dump_get_line); - -- rcu_read_lock(); -- list_for_each_entry_rcu(dumper, &dump_list, list) -- dumper->dump(dumper, reason, s1, l1, s2, l2); -- rcu_read_unlock(); -+/* -+ * Fill the provided buffer with as many of the the *youngest* kmsg records -+ * that fit into it. Repeated calls will fill the buffer with the next block -+ * of older records, not including the former ones. A return value of FALSE -+ * indicate that all records are read, including the oldest one. ++ ++/** ++ * kmsg_dump_get_buffer - copy kmsg log lines ++ * @dumper: registered kmsg dumper ++ * @syslog: include the "<4>" prefixes ++ * @line: buffer to copy the line to ++ * @size: maximum size of the buffer ++ * @len: length of line placed into buffer ++ * ++ * Start at the end of the kmsg buffer and fill the provided buffer ++ * with as many of the the *youngest* kmsg records that fit into it. ++ * If the buffer is large enough, all available kmsg records will be ++ * copied with a single call. ++ * ++ * Consecutive calls will fill the buffer with the next block of ++ * available older records, not including the earlier retrieved ones. ++ * ++ * A return value of FALSE indicate that there are no more records to ++ * read. + */ +bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, + char *buf, size_t size, size_t *len) @@ -519,16 +554,41 @@ + + idx = log_next(idx); + seq++; -+ } + } + + dumper->next_seq = next_seq; + dumper->next_idx = next_idx; + ret = true; -+ raw_spin_unlock_irqrestore(&logbuf_lock, flags); + raw_spin_unlock_irqrestore(&logbuf_lock, flags); +out: + if (len) + *len = l; + return ret; - } ++} +EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); + +- rcu_read_lock(); +- list_for_each_entry_rcu(dumper, &dump_list, list) +- dumper->dump(dumper, reason, s1, l1, s2, l2); +- rcu_read_unlock(); ++/** ++ * kmsg_dump_rewind - reset the interator ++ * @dumper: registered kmsg dumper ++ * ++ * Reset the dumper's iterator so that kmsg_dump_get_line() and ++ * kmsg_dump_get_buffer() can be called again and used multiple ++ * times within the same dumper.dump() callback. ++ */ ++void kmsg_dump_rewind(struct kmsg_dumper *dumper) ++{ ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&logbuf_lock, flags); ++ dumper->cur_seq = clear_seq; ++ dumper->cur_idx = clear_idx; ++ dumper->next_seq = log_next_seq; ++ dumper->next_idx = log_next_idx; ++ raw_spin_unlock_irqrestore(&logbuf_lock, flags); + } ++EXPORT_SYMBOL_GPL(kmsg_dump_rewind); #endif |