From: Andrea Arcangeli Allow the printk log buffer size to be selected with a __setup parameter, `log_buf_len=N', where N must be a power-of-two. The default, initial statically allocated buffer size is still determined via kernel config. Documentation/kernel-parameters.txt | 4 + kernel/printk.c | 84 +++++++++++++++++++++++++++--------- 2 files changed, 69 insertions(+), 19 deletions(-) diff -puN kernel/printk.c~selectable-logbuf-size kernel/printk.c --- 25/kernel/printk.c~selectable-logbuf-size 2003-10-02 00:11:18.000000000 -0700 +++ 25-akpm/kernel/printk.c 2003-10-02 00:11:18.000000000 -0700 @@ -29,11 +29,11 @@ #include #include #include +#include #include -#define LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) -#define LOG_BUF_MASK (LOG_BUF_LEN-1) +#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) /* printk's without a loglevel use this.. */ #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ @@ -68,17 +68,21 @@ struct console *console_drivers; */ static spinlock_t logbuf_lock = SPIN_LOCK_UNLOCKED; -static char log_buf[LOG_BUF_LEN]; +static char __log_buf[__LOG_BUF_LEN]; +static char *log_buf = __log_buf; +static int log_buf_len = __LOG_BUF_LEN; + +#define LOG_BUF_MASK (log_buf_len-1) #define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK]) /* - * The indices into log_buf are not constrained to LOG_BUF_LEN - they + * The indices into log_buf are not constrained to log_buf_len - they * must be masked before subscripting */ -static unsigned long log_start; /* Index into log_buf: next char to be read by syslog() */ -static unsigned long con_start; /* Index into log_buf: next char to be sent to consoles */ -static unsigned long log_end; /* Index into log_buf: most-recently-written-char + 1 */ -static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */ +static unsigned long log_start; /* Index into log_buf: next char to be read by syslog() */ +static unsigned long con_start; /* Index into log_buf: next char to be sent to consoles */ +static unsigned long log_end; /* Index into log_buf: most-recently-written-char + 1 */ +static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */ struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; static int preferred_console = -1; @@ -141,6 +145,45 @@ static int __init console_setup(char *st __setup("console=", console_setup); +static int __init log_buf_len_setup(char *str) +{ + unsigned long size = memparse(str, &str); + + if (size > log_buf_len) { + unsigned long start, dest_idx, offset; + char * new_log_buf; + + new_log_buf = alloc_bootmem(size); + if (!new_log_buf) { + printk("log_buf_len: allocation failed\n"); + goto out; + } + + spin_lock_irq(&logbuf_lock); + log_buf_len = size; + log_buf = new_log_buf; + + offset = start = min(con_start, log_start); + dest_idx = 0; + while (start != log_end) { + log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)]; + start++; + dest_idx++; + } + log_start -= offset; + con_start -= offset; + log_end -= offset; + spin_unlock_irq(&logbuf_lock); + + printk("log_buf_len: %d\n", log_buf_len); + } +out: + + return 1; +} + +__setup("log_buf_len=", log_buf_len_setup); + /* * Commands to do_syslog: * @@ -213,8 +256,8 @@ int do_syslog(int type, char __user * bu if (error) goto out; count = len; - if (count > LOG_BUF_LEN) - count = LOG_BUF_LEN; + if (count > log_buf_len) + count = log_buf_len; spin_lock_irq(&logbuf_lock); if (count > logged_chars) count = logged_chars; @@ -229,7 +272,7 @@ int do_syslog(int type, char __user * bu */ for(i = 0; i < count && !error; i++) { j = limit-1-i; - if (j+LOG_BUF_LEN < log_end) + if (j + log_buf_len < log_end) break; c = LOG_BUF(j); spin_unlock_irq(&logbuf_lock); @@ -302,12 +345,15 @@ static void __call_console_drivers(unsig /* * Write out chars from start to end - 1 inclusive */ -static void _call_console_drivers(unsigned long start, unsigned long end, int msg_log_level) +static void _call_console_drivers(unsigned long start, + unsigned long end, int msg_log_level) { - if (msg_log_level < console_loglevel && console_drivers && start != end) { + if (msg_log_level < console_loglevel && + console_drivers && start != end) { if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) { /* wrapped write */ - __call_console_drivers(start & LOG_BUF_MASK, LOG_BUF_LEN); + __call_console_drivers(start & LOG_BUF_MASK, + log_buf_len); __call_console_drivers(0, end & LOG_BUF_MASK); } else { __call_console_drivers(start, end); @@ -370,11 +416,11 @@ static void emit_log_char(char c) { LOG_BUF(log_end) = c; log_end++; - if (log_end - log_start > LOG_BUF_LEN) - log_start = log_end - LOG_BUF_LEN; - if (log_end - con_start > LOG_BUF_LEN) - con_start = log_end - LOG_BUF_LEN; - if (logged_chars < LOG_BUF_LEN) + if (log_end - log_start > log_buf_len) + log_start = log_end - log_buf_len; + if (log_end - con_start > log_buf_len) + con_start = log_end - log_buf_len; + if (logged_chars < log_buf_len) logged_chars++; } diff -puN Documentation/kernel-parameters.txt~selectable-logbuf-size Documentation/kernel-parameters.txt --- 25/Documentation/kernel-parameters.txt~selectable-logbuf-size 2003-10-02 00:11:18.000000000 -0700 +++ 25-akpm/Documentation/kernel-parameters.txt 2003-10-02 00:11:18.000000000 -0700 @@ -460,6 +460,10 @@ running once the system is up. logibm_irq= [HW,MOUSE] Logitech Bus Mouse Driver Format: + log_buf_len=n Sets the size of the printk ring buffer, in bytes. + Format is n, nk, nM. n must be a power of two. The + default is set in kernel config. + lp=0 [LP] Specify parallel ports to use, e.g, lp=port[,port...] lp=none,parport0 (lp0 not configured, lp1 uses lp=reset first parallel port). 'lp=0' disables the _