Commit 96fcef0a authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] boot-time selectable log buffer size

From: Andrea Arcangeli <andrea@suse.de>

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.
parent cedc5632
......@@ -460,6 +460,10 @@ running once the system is up.
logibm_irq= [HW,MOUSE] Logitech Bus Mouse Driver
Format: <irq>
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
......
......@@ -29,11 +29,11 @@
#include <linux/delay.h>
#include <linux/smp.h>
#include <linux/security.h>
#include <linux/bootmem.h>
#include <asm/uaccess.h>
#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 *str)
__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 * buf, int len)
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 * buf, int len)
*/
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(unsigned long start, unsigned long end)
/*
* 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++;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment