From 6c1639058fcee146dc78acfe5f9db3b600651d7e Mon Sep 17 00:00:00 2001 From: Tony Layher Date: Thu, 14 May 2015 18:44:25 +0200 Subject: [PATCH] Enable pstore/ramoops dump for kernel panics. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated to include options for proper last_kmsg generation CONFIG_SEC_DEBUG_NOCACHE_LOG_IN_LEVEL_LOW=y CONFIG_PRINTK_PROCESS=y CONFIG_SEC_DEBUG_LOW_LOG=y Squashed commit of the following: commit cf46f03896a2010cd291607e143638aea86cf5bd Author: Tony Layher Date: Sun Jan 25 23:34:40 2015 -0500 trlte: enable panic dumps in defconfig and carve out mem region Change-Id: Ifee3321b13a2fbd908a62f442b1a3656f793373d commit 683306b316e6296084fbe6d53dcad9824dd525ad Author: Yi-wei Zhao Date: Thu Aug 7 13:59:41 2014 -0500 fs/pstore: handle panic kmsg dump There are two changes: 1. read 'record size' and 'dump oops' from device tree. 2. only write for KMSG_DUMP_PANIC. When oops happens (panic_on_oops = 1), both oops_exit() and panic() will dump kmsg. Skip KMSG_DUMP_OOPS to avoid dump kmsg twice. Signed-off-by: Yi-wei Zhao Reviewed-by: Hong-Mei Li commit 74305f95eccb13b0658817b0cd5c08b1fb18008d Author: Arve Hjønnevåg Date: Fri May 2 20:23:21 2014 -0700 pstore/ram: Add ramoops_console_write_buf api Allow writing into the ramoops console buffer. Change-Id: Iff0d69b562e4dae33ea7f8d19412227bebb17e47 Signed-off-by: Arve Hjønnevåg Signed-off-by: Patrick Tjin Conflicts: fs/pstore/ram.c commit 0e9158f4623586c10050471ce20298f99b4063f9 Author: Yuanyuan Zhong Date: Tue Jun 10 16:20:27 2014 -0500 pstore/ram: export map/unmap functions Export persistent_ram_map() and persistent_ram_unmap() as general purpose functions for mapping and unmapping reserved memory buffer. Signed-off-by: Yuanyuan Zhong Reviewed-by: Yi-Wei Zhao commit 5a7438174d61d26b6d7e321eedabb0801b5b660d Author: Yuanyuan Zhong Date: Tue Jun 10 14:23:07 2014 -0500 pstore/ram: allow annotation appending Existing pstore ram annotation stores messages and exports them after reset. Add function which can be used to append messages to the annotation after reset and before they are exported to annotation-ramoops file. Signed-off-by: Yuanyuan Zhong Reviewed-by: Yi-Wei Zhao commit a950f7ff89cae0a0d4bced57fc94bff218a25e16 Author: Dmitry Ornatsky Date: Tue Apr 8 08:11:06 2014 -0500 fs: pstore: add annotation support Add annotation type prz support to pstore. Publish annotate function for kernel modules. On warm power up pstore will make annotation information found in new ramprz available in annotation-ramoops file. Signed-off-by: Dmitry Ornatsky Reviewed-by: Russell Knize commit 7bbbdcacd7b11d02c7e70e875f04d24c6a423b86 Author: Yi-wei Zhao Date: Mon Mar 31 19:28:35 2014 -0500 fs:pstore:ramoops: config mem from dt configure the start & size of ramoops memory using device tree. the 'dummy' device is no harm as long as initial mem_size is zero. Signed-off-by: Yi-wei Zhao Reviewed-by: Jeffrey Carlyle Change-Id: I371bfdcfc0bb4dca76c40ed03705ad32fd8b97ab --- arch/arm/boot/dts/qcom/apq8084.dtsi | 15 +++ arch/arm/configs/apq8084_sec_defconfig | 6 + fs/pstore/Kconfig | 14 +++ fs/pstore/inode.c | 16 ++- fs/pstore/platform.c | 46 +++++++ fs/pstore/ram.c | 136 +++++++++++++++++++-- fs/pstore/ram_core.c | 159 +++++++++++++++++++++++++ include/linux/pstore.h | 2 + include/linux/pstore_ram.h | 14 +++ 9 files changed, 394 insertions(+), 14 deletions(-) diff --git a/arch/arm/boot/dts/qcom/apq8084.dtsi b/arch/arm/boot/dts/qcom/apq8084.dtsi index 807c944b6c56..1c92d4a3663b 100644 --- a/arch/arm/boot/dts/qcom/apq8084.dtsi +++ b/arch/arm/boot/dts/qcom/apq8084.dtsi @@ -72,6 +72,21 @@ #size-cells = <1>; ranges = <0 0 0 0xffffffff>; + ramoops { + compatible = "ramoops"; + status = "ok"; + android,ramoops-buffer-start = <0x3e9e0000>; + android,ramoops-buffer-size = <0x100000>; + android,ramoops-console-size = <0x80000>; + android,ramoops-record-size = <0x7F800>; + android,ramoops-annotate-size = <0x800>; + android,ramoops-dump-oops = <0x1>; + android,ramoops-hole { + compatible = "qcom,msm-contig-mem"; + qcom,memblock-reserve = <0x3e9e0000 0x100000>; + }; + }; + intc: interrupt-controller@f9000000 { compatible = "qcom,msm-qgic2"; interrupt-controller; diff --git a/arch/arm/configs/apq8084_sec_defconfig b/arch/arm/configs/apq8084_sec_defconfig index 39a4717e68ef..8bd0a155ff80 100755 --- a/arch/arm/configs/apq8084_sec_defconfig +++ b/arch/arm/configs/apq8084_sec_defconfig @@ -638,6 +638,12 @@ CONFIG_CRYPTO_LZO=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE_RAM_ANNOTATION_APPEND=y +CONFIG_PRINTK_PROCESS=y +CONFIG_SEC_DEBUG_NOCACHE_LOG_IN_LEVEL_LOW=y +CONFIG_SEC_DEBUG_LOW_LOG=y CONFIG_F2FS_FS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index ca71db69da07..134f08c97d75 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -48,3 +48,17 @@ config PSTORE_RAM "ramoops.ko". For more information, see Documentation/ramoops.txt. + +config PSTORE_RAM_ANNOTATION_APPEND + bool "Allow appending messages to pstore ram annotation" + default n + depends on PSTORE_RAM + help + Existing pstore ram annotation stores messages and exports them + after reset. Sometimes only after reset can we do some postmortem + analysis. This adds function which can be used to append the + analysis info to pstore ram annotation. The function should only + be used before pstore ram annotation is exported. It's safe to use + the function before pstore is initialized. Content will be buffered + and merged to annotation-ramoops file. + If unsure, say N. diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index e4bcb2cf055a..66c72df7bd8e 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -313,22 +313,26 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, switch (type) { case PSTORE_TYPE_DMESG: - sprintf(name, "dmesg-%s-%lld", psname, id); + snprintf(name, PSTORE_NAMELEN, "dmesg-%s-%lld", psname, id); break; case PSTORE_TYPE_CONSOLE: - sprintf(name, "console-%s", psname); + snprintf(name, PSTORE_NAMELEN, "console-%s", psname); break; case PSTORE_TYPE_FTRACE: - sprintf(name, "ftrace-%s", psname); + snprintf(name, PSTORE_NAMELEN, "ftrace-%s", psname); break; case PSTORE_TYPE_MCE: - sprintf(name, "mce-%s-%lld", psname, id); + snprintf(name, PSTORE_NAMELEN, "mce-%s-%lld", psname, id); + break; + case PSTORE_TYPE_ANNOTATE: + snprintf(name, PSTORE_NAMELEN, "annotate-%s", psname); break; case PSTORE_TYPE_UNKNOWN: - sprintf(name, "unknown-%s-%lld", psname, id); + snprintf(name, PSTORE_NAMELEN, "unknown-%s-%lld", psname, id); break; default: - sprintf(name, "type%d-%s-%lld", type, psname, id); + snprintf(name, PSTORE_NAMELEN, "type%d-%s-%lld", + type, psname, id); break; } diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 86d1038b5a12..63afe0d06af5 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -177,6 +179,48 @@ static struct kmsg_dumper pstore_dumper = { .dump = pstore_dump, }; + + +/* Export function to save device specific power up + * data + * + */ + +int pstore_annotate(const char *buf) +{ + unsigned cnt = strlen(buf); + const char *end = buf + cnt; + + while (buf < end) { + unsigned long flags; + int ret; + u64 id; + + if (cnt > psinfo->bufsize) + cnt = psinfo->bufsize; + + if (oops_in_progress) { + if (!spin_trylock_irqsave(&psinfo->buf_lock, flags)) + break; + } else { + spin_lock_irqsave(&psinfo->buf_lock, flags); + } + memcpy(psinfo->buf, buf, cnt); + ret = psinfo->write(PSTORE_TYPE_ANNOTATE, 0, &id, 0, 0, + cnt, psinfo); + spin_unlock_irqrestore(&psinfo->buf_lock, flags); + + pr_debug("ret %d wrote bytes %d\n", ret, cnt); + buf += cnt; + cnt = end - buf; + } + + return 0; + +} +EXPORT_SYMBOL_GPL(pstore_annotate); + + #ifdef CONFIG_PSTORE_CONSOLE static void pstore_console_write(struct console *con, const char *s, unsigned c) { @@ -273,6 +317,7 @@ int pstore_register(struct pstore_info *psi) msecs_to_jiffies(pstore_update_ms); add_timer(&pstore_timer); } + pr_info("psi registered\n"); return 0; } @@ -309,6 +354,7 @@ void pstore_get_records(int quiet) buf = NULL; if (rc && (rc != -EEXIST || !quiet)) failed++; + pr_info("Found record type %d, psi name %s\n", type, psi->name); } if (psi->close) psi->close(psi); diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 058f17f0b466..09475cdcc8e5 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -34,6 +34,7 @@ #include #include #include +#include #define RAMOOPS_KERNMSG_HDR "====" #define MIN_MEM_SIZE 4096UL @@ -51,6 +52,10 @@ static ulong ramoops_ftrace_size = MIN_MEM_SIZE; module_param_named(ftrace_size, ramoops_ftrace_size, ulong, 0400); MODULE_PARM_DESC(ftrace_size, "size of ftrace log"); +static ulong ramoops_annotate_size = MIN_MEM_SIZE; +module_param_named(annotate_size, ramoops_annotate_size, ulong, 0400); +MODULE_PARM_DESC(annotate_size, "size of annotation"); + static ulong mem_address; module_param(mem_address, ulong, 0400); MODULE_PARM_DESC(mem_address, @@ -77,11 +82,13 @@ struct ramoops_context { struct persistent_ram_zone **przs; struct persistent_ram_zone *cprz; struct persistent_ram_zone *fprz; + struct persistent_ram_zone *aprz; phys_addr_t phys_addr; unsigned long size; size_t record_size; size_t console_size; size_t ftrace_size; + size_t annotate_size; int dump_oops; struct persistent_ram_ecc_info ecc_info; unsigned int max_dump_cnt; @@ -89,6 +96,7 @@ struct ramoops_context { unsigned int dump_read_cnt; unsigned int console_read_cnt; unsigned int ftrace_read_cnt; + unsigned int annotate_read_cnt; struct pstore_info pstore; }; @@ -101,6 +109,7 @@ static int ramoops_pstore_open(struct pstore_info *psi) cxt->dump_read_cnt = 0; cxt->console_read_cnt = 0; + cxt->annotate_read_cnt = 0; return 0; } @@ -143,12 +152,20 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt, cxt->max_dump_cnt, id, type, PSTORE_TYPE_DMESG, 1); - if (!prz) + if (!prz) { prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt, 1, id, type, PSTORE_TYPE_CONSOLE, 0); + if (prz && !persistent_ram_old_size(prz)) + persistent_ram_annotation_merge(NULL); + } if (!prz) prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt, 1, id, type, PSTORE_TYPE_FTRACE, 0); + if (!prz) { + prz = ramoops_get_next_prz(&cxt->aprz, &cxt->annotate_read_cnt, + 1, id, type, PSTORE_TYPE_ANNOTATE, 0); + persistent_ram_annotation_merge(prz); + } if (!prz) return 0; @@ -212,6 +229,11 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, return -ENOMEM; persistent_ram_write(cxt->fprz, buf, size); return 0; + } else if (type == PSTORE_TYPE_ANNOTATE) { + if (!cxt->aprz) + return -ENOMEM; + persistent_ram_write(cxt->aprz, buf, size); + return 0; } if (type != PSTORE_TYPE_DMESG) @@ -220,8 +242,7 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, /* Out of the various dmesg dump types, ramoops is currently designed * to only store crash logs, rather than storing general kernel logs. */ - if (reason != KMSG_DUMP_OOPS && - reason != KMSG_DUMP_PANIC) + if (reason != KMSG_DUMP_PANIC) return -EINVAL; /* Skip Oopes when configured to do so. */ @@ -269,6 +290,9 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count, case PSTORE_TYPE_FTRACE: prz = cxt->fprz; break; + case PSTORE_TYPE_ANNOTATE: + prz = cxt->aprz; + break; default: return -EINVAL; } @@ -383,15 +407,93 @@ void notrace ramoops_console_write_buf(const char *buf, size_t size) persistent_ram_write(cxt->cprz, buf, size); } +#ifdef CONFIG_OF +static struct of_device_id ramoops_of_match[] = { + { .compatible = "ramoops", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, ramoops_of_match); +static void ramoops_of_init(struct platform_device *pdev) +{ + const struct device *dev = &pdev->dev; + struct ramoops_platform_data *pdata; + struct device_node *np = pdev->dev.of_node; + u32 start, size, console, annotate = 0; + u32 record, oops; + int ret; + + pdata = dev_get_drvdata(dev); + if (!pdata) { + pr_err("private data is empty!\n"); + return; + } + ret = of_property_read_u32(np, "android,ramoops-buffer-start", + &start); + if (ret) + return; + + ret = of_property_read_u32(np, "android,ramoops-buffer-size", + &size); + if (ret) + return; + + ret = of_property_read_u32(np, "android,ramoops-console-size", + &console); + if (ret) + return; + + ret = of_property_read_u32(np, "android,ramoops-annotate-size", + &annotate); + if (ret) + pr_info("annotation buffer not configured"); + + ret = of_property_read_u32(np, "android,ramoops-record-size", + &record); + if (ret) + pr_info("record buffer not configured"); + + ret = of_property_read_u32(np, "android,ramoops-dump-oops", + &oops); + if (ret) + pr_info("oops not configured"); + + pdata->mem_address = start; + pdata->mem_size = size; + pdata->console_size = console; + pdata->annotate_size = annotate; + pdata->record_size = record; + pdata->dump_oops = (int)oops; +} +#else +static inline void ramoops_of_init(struct platform_device *pdev) +{ + return; +} +#endif + static int ramoops_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct ramoops_platform_data *pdata = pdev->dev.platform_data; + struct ramoops_platform_data *pdata; struct ramoops_context *cxt = &oops_cxt; size_t dump_mem_sz; phys_addr_t paddr; int err = -EINVAL; + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + pr_err("could not allocate ramoops_platform_data\n"); + return -ENOMEM; + } + + err = dev_set_drvdata(dev, pdata); + if (err) + goto fail_out; + + if (pdev->dev.of_node) + ramoops_of_init(pdev); + /* Only a single ramoops area allowed at a time, so fail extra * probes. */ @@ -399,7 +501,7 @@ static int ramoops_probe(struct platform_device *pdev) goto fail_out; if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size && - !pdata->ftrace_size)) { + !pdata->ftrace_size && !pdata->annotate_size)) { pr_err("The memory size and the record/console size must be " "non-zero\n"); goto fail_out; @@ -413,6 +515,13 @@ static int ramoops_probe(struct platform_device *pdev) pdata->console_size = rounddown_pow_of_two(pdata->console_size); if (!is_power_of_2(pdata->ftrace_size)) pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size); + if (!is_power_of_2(pdata->annotate_size)) + pdata->annotate_size = + rounddown_pow_of_two(pdata->annotate_size); + + pr_debug("All %#lx record %#lx console %#lx ftrace %#lx annotate %#lx\n", + pdata->mem_size, pdata->record_size, pdata->console_size, + pdata->ftrace_size, pdata->annotate_size); cxt->dump_read_cnt = 0; cxt->size = pdata->mem_size; @@ -420,12 +529,14 @@ static int ramoops_probe(struct platform_device *pdev) cxt->record_size = pdata->record_size; cxt->console_size = pdata->console_size; cxt->ftrace_size = pdata->ftrace_size; + cxt->annotate_size = pdata->annotate_size; cxt->dump_oops = pdata->dump_oops; cxt->ecc_info = pdata->ecc_info; paddr = cxt->phys_addr; - dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size; + dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size + - cxt->annotate_size; err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz); if (err) goto fail_out; @@ -440,10 +551,15 @@ static int ramoops_probe(struct platform_device *pdev) if (err) goto fail_init_fprz; - if (!cxt->przs && !cxt->cprz && !cxt->fprz) { + err = ramoops_init_prz(dev, cxt, &cxt->aprz, &paddr, + cxt->annotate_size, 0); + if (err) + goto fail_init_aprz; + + if (!cxt->przs && !cxt->cprz && !cxt->fprz && !cxt->aprz) { pr_err("memory size too small, minimum is %zu\n", cxt->console_size + cxt->record_size + - cxt->ftrace_size); + cxt->ftrace_size + cxt->annotate_size); err = -EINVAL; goto fail_cnt; } @@ -493,6 +609,8 @@ static int ramoops_probe(struct platform_device *pdev) cxt->pstore.bufsize = 0; cxt->max_dump_cnt = 0; fail_cnt: + kfree(cxt->aprz); +fail_init_aprz: kfree(cxt->fprz); fail_init_fprz: kfree(cxt->cprz); @@ -528,6 +646,7 @@ static struct platform_driver ramoops_driver = { .remove = __exit_p(ramoops_remove), .driver = { .name = "ramoops", + .of_match_table = of_match_ptr(ramoops_of_match), .owner = THIS_MODULE, }, }; @@ -550,6 +669,7 @@ static void ramoops_register_dummy(void) dummy_data->record_size = record_size; dummy_data->console_size = ramoops_console_size; dummy_data->ftrace_size = ramoops_ftrace_size; + dummy_data->annotate_size = ramoops_annotate_size; dummy_data->dump_oops = dump_oops; /* * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index 59337326e288..d6298b39b017 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -256,6 +256,144 @@ static void notrace persistent_ram_update(struct persistent_ram_zone *prz, persistent_ram_update_ecc(prz, start, count); } +#ifdef CONFIG_PSTORE_RAM_ANNOTATION_APPEND +struct praa_buf { + struct list_head list; + int size, space; + char data[]; +}; + +struct persistent_ram_annotation_append_buffer { + spinlock_t lock; /* protect list and buf */ + struct list_head list; + struct praa_buf *buf; + int total_size; + int stop; +} praa_buffer = { + .lock = __SPIN_LOCK_UNLOCKED(praa_buffer.lock), + .list = LIST_HEAD_INIT(praa_buffer.list), +}; + +int persistent_ram_annotation_append(const char *fmt, ...) +{ + va_list args; + unsigned long flags; + int len = 0; + char line_buf[512]; + struct praa_buf *buf; + + va_start(args, fmt); + len += vsnprintf(line_buf + len, sizeof(line_buf) - len, fmt, args); + va_end(args); + + spin_lock_irqsave(&praa_buffer.lock, flags); + if (praa_buffer.stop) { + spin_unlock_irqrestore(&praa_buffer.lock, flags); + pr_err("%s() called too late by %pf()\n", __func__, + __builtin_return_address(0)); + return 0; + } + + while (1) { + if (!praa_buffer.buf) { + buf = (struct praa_buf *) __get_free_page(GFP_ATOMIC); + if (buf) { + buf->size = 0; + buf->space = PAGE_SIZE - 1 - + offsetof(struct praa_buf, data); + praa_buffer.buf = buf; + } else { + pr_err("%s NOMEM\n", __func__); + len = 0; + break; + } + } + buf = praa_buffer.buf; + if (len + 1 > buf->space) { + buf->data[buf->size] = '\0'; + list_add_tail(&buf->list, &praa_buffer.list); + praa_buffer.total_size += buf->size; + praa_buffer.buf = NULL; + continue; + } + memcpy(&buf->data[buf->size], line_buf, len); + buf->space -= len; + buf->size += len; + break; + } + spin_unlock_irqrestore(&praa_buffer.lock, flags); + return len; +} + +static int persistent_ram_annotation_append_stop(void) +{ + int ret; + unsigned long flags; + struct praa_buf *buf; + spin_lock_irqsave(&praa_buffer.lock, flags); + if (praa_buffer.stop) { + spin_unlock_irqrestore(&praa_buffer.lock, flags); + return 0; + } + praa_buffer.stop = 1; + if (praa_buffer.buf) { + buf = praa_buffer.buf; + praa_buffer.buf = NULL; + buf->data[buf->size] = '\0'; + list_add_tail(&buf->list, &praa_buffer.list); + praa_buffer.total_size += buf->size; + } + ret = praa_buffer.total_size; + spin_unlock_irqrestore(&praa_buffer.lock, flags); + return ret; +} + +static void persistent_ram_annotation_append_push(char *ptr) +{ + unsigned long flags; + struct praa_buf *buf, *n; + + spin_lock_irqsave(&praa_buffer.lock, flags); + list_for_each_entry_safe(buf, n, &praa_buffer.list, list) { + if (ptr) { + memcpy(ptr, buf->data, buf->size); + ptr += buf->size; + } + list_del(&buf->list); + praa_buffer.total_size -= buf->size; + free_page((unsigned long)buf); + } + spin_unlock_irqrestore(&praa_buffer.lock, flags); +} + +void persistent_ram_annotation_merge(struct persistent_ram_zone *prz) +{ + size_t ext_size; + char *old_log2; + + ext_size = persistent_ram_annotation_append_stop(); + if (ext_size) { + if (!prz) { + persistent_ram_annotation_append_push(NULL); + pr_info("%s: discarded %zu\n", __func__, ext_size); + return; + } + old_log2 = krealloc(prz->old_log, + prz->old_log_size + ext_size, GFP_KERNEL); + if (old_log2) { + persistent_ram_annotation_append_push(old_log2 + + prz->old_log_size); + prz->old_log = old_log2; + prz->old_log_size += ext_size; + pr_info("%s: merged %zu\n", __func__, ext_size); + } else { + pr_err("%s: cannot merge %zu\n", __func__, ext_size); + persistent_ram_annotation_append_push(NULL); + } + } +} +#endif + void persistent_ram_save_old(struct persistent_ram_zone *prz) { struct persistent_ram_buffer *buffer = prz->buffer; @@ -398,6 +536,27 @@ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size, return 0; } +void *persistent_ram_map(phys_addr_t start, phys_addr_t size) +{ + void *vaddr; + + if (pfn_valid(start >> PAGE_SHIFT)) + vaddr = persistent_ram_vmap(start, size); + else + vaddr = persistent_ram_iomap(start, size); + return vaddr; +} + +void persistent_ram_unmap(void *vaddr, phys_addr_t start, phys_addr_t size) +{ + if (pfn_valid(start >> PAGE_SHIFT)) { + vunmap(vaddr); + } else { + iounmap(vaddr); + release_mem_region(start, size); + } +} + static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig, struct persistent_ram_ecc_info *ecc_info) { diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 75d01760c911..70782dbafa20 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -35,6 +35,7 @@ enum pstore_type_id { PSTORE_TYPE_MCE = 1, PSTORE_TYPE_CONSOLE = 2, PSTORE_TYPE_FTRACE = 3, + PSTORE_TYPE_ANNOTATE = 4, PSTORE_TYPE_UNKNOWN = 255 }; @@ -69,6 +70,7 @@ struct pstore_info { #ifdef CONFIG_PSTORE extern int pstore_register(struct pstore_info *); extern bool pstore_cannot_block_path(enum kmsg_dump_reason reason); +extern int pstore_annotate(const char *buf); #else static inline int pstore_register(struct pstore_info *psi) diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index 9e370618352a..8851da88eb69 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -66,6 +66,19 @@ void *persistent_ram_old(struct persistent_ram_zone *prz); void persistent_ram_free_old(struct persistent_ram_zone *prz); ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz, char *str, size_t len); +#ifdef CONFIG_PSTORE_RAM_ANNOTATION_APPEND +__printf(1, 2) int persistent_ram_annotation_append(const char *fmt, ...); +void persistent_ram_annotation_merge(struct persistent_ram_zone *prz); +#else +static inline __printf(1, 2) void persistent_ram_annotation_append( + const char *fmt, ...) { }; +static inline void persistent_ram_annotation_merge( + struct persistent_ram_zone *prz) { }; +#endif +void *persistent_ram_map(phys_addr_t start, phys_addr_t size); +void persistent_ram_unmap(void *vaddr, phys_addr_t start, phys_addr_t size); + +void ramoops_console_write_buf(const char *buf, size_t size); void ramoops_console_write_buf(const char *buf, size_t size); @@ -81,6 +94,7 @@ struct ramoops_platform_data { unsigned long record_size; unsigned long console_size; unsigned long ftrace_size; + unsigned long annotate_size; int dump_oops; struct persistent_ram_ecc_info ecc_info; };