aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/setup.c2
-rw-r--r--include/linux/printk.h7
-rw-r--r--init/main.c1
-rw-r--r--kernel/printk.c87
4 files changed, 68 insertions, 29 deletions
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 605e5ae19c7f..a3e5948670c2 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -946,6 +946,8 @@ void __init setup_arch(char **cmdline_p)
946 if (init_ohci1394_dma_early) 946 if (init_ohci1394_dma_early)
947 init_ohci1394_dma_on_all_controllers(); 947 init_ohci1394_dma_on_all_controllers();
948#endif 948#endif
949 /* Allocate bigger log buffer */
950 setup_log_buf(1);
949 951
950 reserve_initrd(); 952 reserve_initrd();
951 953
diff --git a/include/linux/printk.h b/include/linux/printk.h
index ee048e77e1ae..0101d55d9651 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -1,6 +1,8 @@
1#ifndef __KERNEL_PRINTK__ 1#ifndef __KERNEL_PRINTK__
2#define __KERNEL_PRINTK__ 2#define __KERNEL_PRINTK__
3 3
4#include <linux/init.h>
5
4extern const char linux_banner[]; 6extern const char linux_banner[];
5extern const char linux_proc_banner[]; 7extern const char linux_proc_banner[];
6 8
@@ -113,6 +115,7 @@ extern int dmesg_restrict;
113extern int kptr_restrict; 115extern int kptr_restrict;
114 116
115void log_buf_kexec_setup(void); 117void log_buf_kexec_setup(void);
118void __init setup_log_buf(int early);
116#else 119#else
117static inline __attribute__ ((format (printf, 1, 0))) 120static inline __attribute__ ((format (printf, 1, 0)))
118int vprintk(const char *s, va_list args) 121int vprintk(const char *s, va_list args)
@@ -137,6 +140,10 @@ static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies,
137static inline void log_buf_kexec_setup(void) 140static inline void log_buf_kexec_setup(void)
138{ 141{
139} 142}
143
144static inline void setup_log_buf(int early)
145{
146}
140#endif 147#endif
141 148
142extern void dump_stack(void) __cold; 149extern void dump_stack(void) __cold;
diff --git a/init/main.c b/init/main.c
index 22da33918aef..d2f1e086bf33 100644
--- a/init/main.c
+++ b/init/main.c
@@ -504,6 +504,7 @@ asmlinkage void __init start_kernel(void)
504 * These use large bootmem allocations and must precede 504 * These use large bootmem allocations and must precede
505 * kmem_cache_init() 505 * kmem_cache_init()
506 */ 506 */
507 setup_log_buf(0);
507 pidhash_init(); 508 pidhash_init();
508 vfs_caches_init_early(); 509 vfs_caches_init_early();
509 sort_main_extable(); 510 sort_main_extable();
diff --git a/kernel/printk.c b/kernel/printk.c
index da8ca817eae3..35185392173f 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -31,6 +31,7 @@
31#include <linux/smp.h> 31#include <linux/smp.h>
32#include <linux/security.h> 32#include <linux/security.h>
33#include <linux/bootmem.h> 33#include <linux/bootmem.h>
34#include <linux/memblock.h>
34#include <linux/syscalls.h> 35#include <linux/syscalls.h>
35#include <linux/kexec.h> 36#include <linux/kexec.h>
36#include <linux/kdb.h> 37#include <linux/kdb.h>
@@ -167,46 +168,74 @@ void log_buf_kexec_setup(void)
167} 168}
168#endif 169#endif
169 170
171/* requested log_buf_len from kernel cmdline */
172static unsigned long __initdata new_log_buf_len;
173
174/* save requested log_buf_len since it's too early to process it */
170static int __init log_buf_len_setup(char *str) 175static int __init log_buf_len_setup(char *str)
171{ 176{
172 unsigned size = memparse(str, &str); 177 unsigned size = memparse(str, &str);
173 unsigned long flags;
174 178
175 if (size) 179 if (size)
176 size = roundup_pow_of_two(size); 180 size = roundup_pow_of_two(size);
177 if (size > log_buf_len) { 181 if (size > log_buf_len)
178 unsigned start, dest_idx, offset; 182 new_log_buf_len = size;
179 char *new_log_buf;
180 183
181 new_log_buf = alloc_bootmem(size); 184 return 0;
182 if (!new_log_buf) { 185}
183 printk(KERN_WARNING "log_buf_len: allocation failed\n"); 186early_param("log_buf_len", log_buf_len_setup);
184 goto out;
185 }
186 187
187 spin_lock_irqsave(&logbuf_lock, flags); 188void __init setup_log_buf(int early)
188 log_buf_len = size; 189{
189 log_buf = new_log_buf; 190 unsigned long flags;
190 191 unsigned start, dest_idx, offset;
191 offset = start = min(con_start, log_start); 192 char *new_log_buf;
192 dest_idx = 0; 193 int free;
193 while (start != log_end) { 194
194 log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)]; 195 if (!new_log_buf_len)
195 start++; 196 return;
196 dest_idx++; 197
197 } 198 if (early) {
198 log_start -= offset; 199 unsigned long mem;
199 con_start -= offset;
200 log_end -= offset;
201 spin_unlock_irqrestore(&logbuf_lock, flags);
202 200
203 printk(KERN_NOTICE "log_buf_len: %d\n", log_buf_len); 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 }
205out:
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#ifdef CONFIG_BOOT_PRINTK_DELAY 240#ifdef CONFIG_BOOT_PRINTK_DELAY
212 241