Add two new functions for reading the kernel log buffer. Their intention is to be used by recovery/dump/debug code so the kernel log can be easily retrieved/parsed in a crash scenario, but they are generic enough for other people to dream up other fun uses. Signed-off-by: Mike Frysinger --- diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 4300bb4..3fcc09e 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -156,6 +156,8 @@ asmlinkage int vprintk(const char *fmt, va_list args) __attribute__ ((format (printf, 1, 0))); asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))) __cold; +extern int log_buf_read(int len, char *buf, int grab_lock); +extern int log_buf_read_byte(int idx, char *byte, int grab_lock); #else static inline int vprintk(const char *s, va_list args) __attribute__ ((format (printf, 1, 0))); @@ -163,6 +165,8 @@ static inline int vprintk(const char *s, va_list args) { return 0; } static inline int printk(const char *s, ...) __attribute__ ((format (printf, 1, 2))); static inline int __cold printk(const char *s, ...) { return 0; } +static inline int log_buf_read(int len, char *buf, int grab_lock) { return 0; } +static inline int log_buf_read_byte(int len, char *buf, int grab_lock) { return 0; } #endif unsigned long int_sqrt(unsigned long); diff --git a/kernel/printk.c b/kernel/printk.c index 051d27e..f08dbf5 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -163,6 +163,71 @@ out: __setup("log_buf_len=", log_buf_len_setup); /* + * Read the log buffer into the supplied buffer. The len option + * tells whether to copy from the beginning (> 0), the end (< 0), or + * just query the number of existing chars. The number of bytes + * actually copied is returned. + */ +int log_buf_read(int len, char *buf, int grab_lock) +{ + unsigned long start, end; + int num_to_copy; + + if (len == 0) + return log_end - log_start; + + if (grab_lock) + spin_lock_irq(&logbuf_lock); + + num_to_copy = min(abs(len), abs(log_end - log_start)); + + if (len < 0) { + start = log_end - num_to_copy; + end = log_end; + } else { + start = log_start; + end = log_start + num_to_copy; + } + + while (start != end) + *buf++ = LOG_BUF(start++); + + if (grab_lock) + spin_unlock_irq(&logbuf_lock); + + return num_to_copy; +} + +/* + * Grab a single byte out of the log buffer. The idx option + * tells whether to index from the beginning (>= 0) or the + * end (< 0) of the buffer. + */ +int log_buf_read_byte(int idx, char *byte, int grab_lock) +{ + int ret = 1; + + if (grab_lock) + spin_lock_irq(&logbuf_lock); + + if (abs(idx) >= log_buf_len || abs(idx) >= logged_chars) { + ret = -1; + goto done; + } + + if (idx < 0) + *byte = LOG_BUF(log_end + idx); + else + *byte = LOG_BUF(log_start + idx); + + done: + if (grab_lock) + spin_unlock_irq(&logbuf_lock); + + return ret; +} + +/* * Commands to do_syslog: * * 0 -- Close the log. Currently a NOP.