diff options
-rw-r--r-- | arch/x86/kernel/setup.c | 2 | ||||
-rw-r--r-- | include/linux/printk.h | 7 | ||||
-rw-r--r-- | init/main.c | 1 | ||||
-rw-r--r-- | kernel/printk.c | 87 |
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 | |||
4 | extern const char linux_banner[]; | 6 | extern const char linux_banner[]; |
5 | extern const char linux_proc_banner[]; | 7 | extern const char linux_proc_banner[]; |
6 | 8 | ||
@@ -113,6 +115,7 @@ extern int dmesg_restrict; | |||
113 | extern int kptr_restrict; | 115 | extern int kptr_restrict; |
114 | 116 | ||
115 | void log_buf_kexec_setup(void); | 117 | void log_buf_kexec_setup(void); |
118 | void __init setup_log_buf(int early); | ||
116 | #else | 119 | #else |
117 | static inline __attribute__ ((format (printf, 1, 0))) | 120 | static inline __attribute__ ((format (printf, 1, 0))) |
118 | int vprintk(const char *s, va_list args) | 121 | int vprintk(const char *s, va_list args) |
@@ -137,6 +140,10 @@ static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, | |||
137 | static inline void log_buf_kexec_setup(void) | 140 | static inline void log_buf_kexec_setup(void) |
138 | { | 141 | { |
139 | } | 142 | } |
143 | |||
144 | static inline void setup_log_buf(int early) | ||
145 | { | ||
146 | } | ||
140 | #endif | 147 | #endif |
141 | 148 | ||
142 | extern void dump_stack(void) __cold; | 149 | extern 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 */ | ||
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 | static int __init log_buf_len_setup(char *str) | 175 | static 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"); | 186 | early_param("log_buf_len", log_buf_len_setup); |
184 | goto out; | ||
185 | } | ||
186 | 187 | ||
187 | spin_lock_irqsave(&logbuf_lock, flags); | 188 | void __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 | } |
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 | #ifdef CONFIG_BOOT_PRINTK_DELAY | 240 | #ifdef CONFIG_BOOT_PRINTK_DELAY |
212 | 241 | ||