Commit 162a7e75 authored by Mike Travis's avatar Mike Travis Committed by Linus Torvalds

printk: allocate kernel log buffer earlier

On larger systems, because of the numerous ACPI, Bootmem and EFI messages,
the static log buffer overflows before the larger one specified by the
log_buf_len param is allocated.  Minimize the overflow by allocating the
new log buffer as soon as possible.

On kernels without memblock, a later call to setup_log_buf from
kernel/init.c is the fallback.

[akpm@linux-foundation.org: coding-style fixes]
[akpm@linux-foundation.org: fix CONFIG_PRINTK=n build]
Signed-off-by: default avatarMike Travis <travis@sgi.com>
Cc: Yinghai Lu <yhlu.kernel@gmail.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Jack Steiner <steiner@sgi.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 95dde501
...@@ -946,6 +946,8 @@ void __init setup_arch(char **cmdline_p) ...@@ -946,6 +946,8 @@ void __init setup_arch(char **cmdline_p)
if (init_ohci1394_dma_early) if (init_ohci1394_dma_early)
init_ohci1394_dma_on_all_controllers(); init_ohci1394_dma_on_all_controllers();
#endif #endif
/* Allocate bigger log buffer */
setup_log_buf(1);
reserve_initrd(); reserve_initrd();
......
#ifndef __KERNEL_PRINTK__ #ifndef __KERNEL_PRINTK__
#define __KERNEL_PRINTK__ #define __KERNEL_PRINTK__
#include <linux/init.h>
extern const char linux_banner[]; extern const char linux_banner[];
extern const char linux_proc_banner[]; extern const char linux_proc_banner[];
...@@ -113,6 +115,7 @@ extern int dmesg_restrict; ...@@ -113,6 +115,7 @@ extern int dmesg_restrict;
extern int kptr_restrict; extern int kptr_restrict;
void log_buf_kexec_setup(void); void log_buf_kexec_setup(void);
void __init setup_log_buf(int early);
#else #else
static inline __attribute__ ((format (printf, 1, 0))) static inline __attribute__ ((format (printf, 1, 0)))
int vprintk(const char *s, va_list args) int vprintk(const char *s, va_list args)
...@@ -137,6 +140,10 @@ static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, ...@@ -137,6 +140,10 @@ static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies,
static inline void log_buf_kexec_setup(void) static inline void log_buf_kexec_setup(void)
{ {
} }
static inline void setup_log_buf(int early)
{
}
#endif #endif
extern void dump_stack(void) __cold; extern void dump_stack(void) __cold;
......
...@@ -504,6 +504,7 @@ asmlinkage void __init start_kernel(void) ...@@ -504,6 +504,7 @@ asmlinkage void __init start_kernel(void)
* These use large bootmem allocations and must precede * These use large bootmem allocations and must precede
* kmem_cache_init() * kmem_cache_init()
*/ */
setup_log_buf(0);
pidhash_init(); pidhash_init();
vfs_caches_init_early(); vfs_caches_init_early();
sort_main_extable(); sort_main_extable();
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/memblock.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/kexec.h> #include <linux/kexec.h>
#include <linux/kdb.h> #include <linux/kdb.h>
...@@ -167,46 +168,74 @@ void log_buf_kexec_setup(void) ...@@ -167,46 +168,74 @@ void log_buf_kexec_setup(void)
} }
#endif #endif
/* requested log_buf_len from kernel cmdline */
static unsigned long __initdata new_log_buf_len;
/* save requested log_buf_len since it's too early to process it */
static int __init log_buf_len_setup(char *str) static int __init log_buf_len_setup(char *str)
{ {
unsigned size = memparse(str, &str); unsigned size = memparse(str, &str);
unsigned long flags;
if (size) if (size)
size = roundup_pow_of_two(size); size = roundup_pow_of_two(size);
if (size > log_buf_len) { if (size > log_buf_len)
unsigned start, dest_idx, offset; new_log_buf_len = size;
char *new_log_buf;
new_log_buf = alloc_bootmem(size); return 0;
if (!new_log_buf) { }
printk(KERN_WARNING "log_buf_len: allocation failed\n"); early_param("log_buf_len", log_buf_len_setup);
goto out;
}
spin_lock_irqsave(&logbuf_lock, flags); void __init setup_log_buf(int early)
log_buf_len = size; {
log_buf = new_log_buf; unsigned long flags;
unsigned start, dest_idx, offset;
offset = start = min(con_start, log_start); char *new_log_buf;
dest_idx = 0; int free;
while (start != log_end) {
log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)]; if (!new_log_buf_len)
start++; return;
dest_idx++;
} if (early) {
log_start -= offset; unsigned long mem;
con_start -= offset;
log_end -= offset;
spin_unlock_irqrestore(&logbuf_lock, flags);
printk(KERN_NOTICE "log_buf_len: %d\n", log_buf_len); mem = memblock_alloc(new_log_buf_len, PAGE_SIZE);
if (mem == MEMBLOCK_ERROR)
return;
new_log_buf = __va(mem);
} else {
new_log_buf = alloc_bootmem_nopanic(new_log_buf_len);
} }
out:
return 1;
}
__setup("log_buf_len=", log_buf_len_setup); if (unlikely(!new_log_buf)) {
pr_err("log_buf_len: %ld bytes not available\n",
new_log_buf_len);
return;
}
spin_lock_irqsave(&logbuf_lock, flags);
log_buf_len = new_log_buf_len;
log_buf = new_log_buf;
new_log_buf_len = 0;
free = __LOG_BUF_LEN - log_end;
offset = start = min(con_start, log_start);
dest_idx = 0;
while (start != log_end) {
unsigned log_idx_mask = start & (__LOG_BUF_LEN - 1);
log_buf[dest_idx] = __log_buf[log_idx_mask];
start++;
dest_idx++;
}
log_start -= offset;
con_start -= offset;
log_end -= offset;
spin_unlock_irqrestore(&logbuf_lock, flags);
pr_info("log_buf_len: %d\n", log_buf_len);
pr_info("early log buf free: %d(%d%%)\n",
free, (free * 100) / __LOG_BUF_LEN);
}
#ifdef CONFIG_BOOT_PRINTK_DELAY #ifdef CONFIG_BOOT_PRINTK_DELAY
......
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