|
@@ -31,6 +31,7 @@
|
|
|
#include <linux/smp.h>
|
|
|
#include <linux/security.h>
|
|
|
#include <linux/bootmem.h>
|
|
|
+#include <linux/memblock.h>
|
|
|
#include <linux/syscalls.h>
|
|
|
#include <linux/kexec.h>
|
|
|
#include <linux/kdb.h>
|
|
@@ -167,46 +168,74 @@ void log_buf_kexec_setup(void)
|
|
|
}
|
|
|
#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)
|
|
|
{
|
|
|
unsigned size = memparse(str, &str);
|
|
|
- unsigned long flags;
|
|
|
|
|
|
if (size)
|
|
|
size = roundup_pow_of_two(size);
|
|
|
- if (size > log_buf_len) {
|
|
|
- unsigned start, dest_idx, offset;
|
|
|
- char *new_log_buf;
|
|
|
+ if (size > log_buf_len)
|
|
|
+ new_log_buf_len = size;
|
|
|
|
|
|
- new_log_buf = alloc_bootmem(size);
|
|
|
- if (!new_log_buf) {
|
|
|
- printk(KERN_WARNING "log_buf_len: allocation failed\n");
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+early_param("log_buf_len", log_buf_len_setup);
|
|
|
|
|
|
- spin_lock_irqsave(&logbuf_lock, flags);
|
|
|
- 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_irqrestore(&logbuf_lock, flags);
|
|
|
+void __init setup_log_buf(int early)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ unsigned start, dest_idx, offset;
|
|
|
+ char *new_log_buf;
|
|
|
+ int free;
|
|
|
+
|
|
|
+ if (!new_log_buf_len)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (early) {
|
|
|
+ unsigned long mem;
|
|
|
|
|
|
- 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
|
|
|
|