Commit 162a7e7500f9664636e649ba59defe541b7c2c60

Authored by Mike Travis
Committed by Linus Torvalds
1 parent 95dde50190

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: Mike 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: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 4 changed files with 68 additions and 29 deletions Side-by-side Diff

arch/x86/kernel/setup.c
... ... @@ -946,6 +946,8 @@
946 946 if (init_ohci1394_dma_early)
947 947 init_ohci1394_dma_on_all_controllers();
948 948 #endif
  949 + /* Allocate bigger log buffer */
  950 + setup_log_buf(1);
949 951  
950 952 reserve_initrd();
951 953  
include/linux/printk.h
1 1 #ifndef __KERNEL_PRINTK__
2 2 #define __KERNEL_PRINTK__
3 3  
  4 +#include <linux/init.h>
  5 +
4 6 extern const char linux_banner[];
5 7 extern const char linux_proc_banner[];
6 8  
... ... @@ -113,6 +115,7 @@
113 115 extern int kptr_restrict;
114 116  
115 117 void log_buf_kexec_setup(void);
  118 +void __init setup_log_buf(int early);
116 119 #else
117 120 static inline __attribute__ ((format (printf, 1, 0)))
118 121 int vprintk(const char *s, va_list args)
... ... @@ -135,6 +138,10 @@
135 138 }
136 139  
137 140 static inline void log_buf_kexec_setup(void)
  141 +{
  142 +}
  143 +
  144 +static inline void setup_log_buf(int early)
138 145 {
139 146 }
140 147 #endif
... ... @@ -504,6 +504,7 @@
504 504 * These use large bootmem allocations and must precede
505 505 * kmem_cache_init()
506 506 */
  507 + setup_log_buf(0);
507 508 pidhash_init();
508 509 vfs_caches_init_early();
509 510 sort_main_extable();
... ... @@ -31,6 +31,7 @@
31 31 #include <linux/smp.h>
32 32 #include <linux/security.h>
33 33 #include <linux/bootmem.h>
  34 +#include <linux/memblock.h>
34 35 #include <linux/syscalls.h>
35 36 #include <linux/kexec.h>
36 37 #include <linux/kdb.h>
37 38  
38 39  
39 40  
40 41  
41 42  
42 43  
43 44  
44 45  
... ... @@ -167,46 +168,74 @@
167 168 }
168 169 #endif
169 170  
  171 +/* requested log_buf_len from kernel cmdline */
  172 +static unsigned long __initdata new_log_buf_len;
  173 +
  174 +/* save requested log_buf_len since it's too early to process it */
170 175 static int __init log_buf_len_setup(char *str)
171 176 {
172 177 unsigned size = memparse(str, &str);
173   - unsigned long flags;
174 178  
175 179 if (size)
176 180 size = roundup_pow_of_two(size);
177   - if (size > log_buf_len) {
178   - unsigned start, dest_idx, offset;
179   - char *new_log_buf;
  181 + if (size > log_buf_len)
  182 + new_log_buf_len = size;
180 183  
181   - new_log_buf = alloc_bootmem(size);
182   - if (!new_log_buf) {
183   - printk(KERN_WARNING "log_buf_len: allocation failed\n");
184   - goto out;
185   - }
  184 + return 0;
  185 +}
  186 +early_param("log_buf_len", log_buf_len_setup);
186 187  
187   - spin_lock_irqsave(&logbuf_lock, flags);
188   - log_buf_len = size;
189   - log_buf = new_log_buf;
  188 +void __init setup_log_buf(int early)
  189 +{
  190 + unsigned long flags;
  191 + unsigned start, dest_idx, offset;
  192 + char *new_log_buf;
  193 + int free;
190 194  
191   - offset = start = min(con_start, log_start);
192   - dest_idx = 0;
193   - while (start != log_end) {
194   - log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)];
195   - start++;
196   - dest_idx++;
197   - }
198   - log_start -= offset;
199   - con_start -= offset;
200   - log_end -= offset;
201   - spin_unlock_irqrestore(&logbuf_lock, flags);
  195 + if (!new_log_buf_len)
  196 + return;
202 197  
203   - printk(KERN_NOTICE "log_buf_len: %d\n", log_buf_len);
  198 + if (early) {
  199 + unsigned long mem;
  200 +
  201 + mem = memblock_alloc(new_log_buf_len, PAGE_SIZE);
  202 + if (mem == MEMBLOCK_ERROR)
  203 + return;
  204 + new_log_buf = __va(mem);
  205 + } else {
  206 + new_log_buf = alloc_bootmem_nopanic(new_log_buf_len);
204 207 }
205   -out:
206   - return 1;
207   -}
208 208  
209   -__setup("log_buf_len=", log_buf_len_setup);
  209 + if (unlikely(!new_log_buf)) {
  210 + pr_err("log_buf_len: %ld bytes not available\n",
  211 + new_log_buf_len);
  212 + return;
  213 + }
  214 +
  215 + spin_lock_irqsave(&logbuf_lock, flags);
  216 + log_buf_len = new_log_buf_len;
  217 + log_buf = new_log_buf;
  218 + new_log_buf_len = 0;
  219 + free = __LOG_BUF_LEN - log_end;
  220 +
  221 + offset = start = min(con_start, log_start);
  222 + dest_idx = 0;
  223 + while (start != log_end) {
  224 + unsigned log_idx_mask = start & (__LOG_BUF_LEN - 1);
  225 +
  226 + log_buf[dest_idx] = __log_buf[log_idx_mask];
  227 + start++;
  228 + dest_idx++;
  229 + }
  230 + log_start -= offset;
  231 + con_start -= offset;
  232 + log_end -= offset;
  233 + spin_unlock_irqrestore(&logbuf_lock, flags);
  234 +
  235 + pr_info("log_buf_len: %d\n", log_buf_len);
  236 + pr_info("early log buf free: %d(%d%%)\n",
  237 + free, (free * 100) / __LOG_BUF_LEN);
  238 +}
210 239  
211 240 #ifdef CONFIG_BOOT_PRINTK_DELAY
212 241