Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1030580Ab2ERW1U (ORCPT ); Fri, 18 May 2012 18:27:20 -0400 Received: from mail-pb0-f46.google.com ([209.85.160.46]:60603 "EHLO mail-pb0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1759724Ab2ERW1N (ORCPT ); Fri, 18 May 2012 18:27:13 -0400 Date: Fri, 18 May 2012 15:25:43 -0700 From: Anton Vorontsov To: Greg Kroah-Hartman , Kees Cook , Colin Cross , Tony Luck Cc: Arnd Bergmann , John Stultz , Shuah Khan , arve@android.com, Rebecca Schultz Zavin , Jesper Juhl , Randy Dunlap , Stephen Boyd , Thomas Meyer , Andrew Morton , Marco Stornelli , WANG Cong , linux-kernel@vger.kernel.org, devel@driverdev.osuosl.org, linaro-kernel@lists.linaro.org, patches@linaro.org, kernel-team@android.com Subject: [PATCH 09/14] pstore/ram: Add console messages handling Message-ID: <20120518222543.GI23089@lizard> References: <20120518222314.GA9425@lizard> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: <20120518222314.GA9425@lizard> User-Agent: Mutt/1.5.21 (2010-09-15) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7451 Lines: 260 The console log size is configurable via ramoops.console_size module option, and the log itself is available via /console-ramoops file. Signed-off-by: Anton Vorontsov --- fs/pstore/ram.c | 107 ++++++++++++++++++++++++++++++++++++++------ include/linux/pstore_ram.h | 1 + 2 files changed, 95 insertions(+), 13 deletions(-) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 54e0676..0fdb3a5 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -41,6 +41,10 @@ module_param(record_size, ulong, 0400); MODULE_PARM_DESC(record_size, "size of each dump done on oops/panic"); +static ulong ramoops_console_size = MIN_MEM_SIZE; +module_param_named(console_size, ramoops_console_size, ulong, 0400); +MODULE_PARM_DESC(console_size, "size of kernel console log"); + static ulong mem_address; module_param(mem_address, ulong, 0400); MODULE_PARM_DESC(mem_address, @@ -63,9 +67,11 @@ MODULE_PARM_DESC(ramoops_ecc, struct ramoops_context { struct persistent_ram_zone **przs; + struct persistent_ram_zone *cprz; phys_addr_t phys_addr; unsigned long size; size_t record_size; + size_t console_size; int dump_oops; bool ecc; unsigned int count; @@ -96,6 +102,9 @@ ramoops_get_dump_prz(u64 id, enum pstore_type_id *type, return NULL; prz = cxt->przs[id]; + + /* Update old/shadowed buffer. */ + persistent_ram_copy_old(prz); if (!persistent_ram_old_size(prz)) return NULL; @@ -104,6 +113,19 @@ ramoops_get_dump_prz(u64 id, enum pstore_type_id *type, return prz; } +static struct persistent_ram_zone * +ramoops_get_console_prz(u64 id, enum pstore_type_id *type, + struct ramoops_context *cxt) +{ + if (id >= cxt->max_count) + return NULL; + + *type = PSTORE_TYPE_CONSOLE; + cxt->read_count = cxt->max_count; + + return cxt->cprz; +} + static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, struct timespec *time, char **buf, @@ -117,14 +139,14 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, prz = ramoops_get_dump_prz(*id, type, cxt); if (!prz) + prz = ramoops_get_console_prz(*id, type, cxt); + if (!prz) return 0; /* TODO(kees): Bogus time for the moment. */ time->tv_sec = 0; time->tv_nsec = 0; - /* Update old/shadowed buffer. */ - persistent_ram_copy_old(prz); size = persistent_ram_old_size(prz); *buf = kmalloc(size, GFP_KERNEL); if (*buf == NULL) @@ -161,7 +183,13 @@ static int ramoops_pstore_write(enum pstore_type_id type, struct persistent_ram_zone *prz = cxt->przs[cxt->count]; size_t hlen; - /* Currently ramoops is designed to only store dmesg dumps. */ + if (type == PSTORE_TYPE_CONSOLE) { + if (!cxt->cprz) + return -ENOMEM; + persistent_ram_write(cxt->cprz, cxt->pstore.buf, size); + return 0; + } + if (type != PSTORE_TYPE_DMESG) return -EINVAL; @@ -198,12 +226,17 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, struct pstore_info *psi) { struct ramoops_context *cxt = psi->data; + struct persistent_ram_zone *prz; - if (id >= cxt->max_dump_count) + if (id >= cxt->max_dump_count && id < cxt->max_count) + prz = cxt->cprz; + else if (id < cxt->max_dump_count) + prz = cxt->przs[id]; + else return -EINVAL; - persistent_ram_free_old(cxt->przs[id]); - persistent_ram_zap(cxt->przs[id]); + persistent_ram_free_old(prz); + persistent_ram_zap(prz); return 0; } @@ -272,6 +305,35 @@ fail_prz: return err; } +static void ramoops_free_cprz(struct ramoops_context *cxt) +{ + kfree(cxt->cprz); +} + +static int ramoops_init_cprz(struct device *dev, struct ramoops_context *cxt, + phys_addr_t *paddr, size_t console_mem_sz) +{ + if (!console_mem_sz) + return 0; + + if (*paddr + console_mem_sz > *paddr + cxt->size) + return -ENOMEM; + + cxt->cprz = persistent_ram_new(*paddr, console_mem_sz, cxt->ecc); + if (IS_ERR(cxt->cprz)) { + int err = PTR_ERR(cxt->cprz); + + dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n", + console_mem_sz, (unsigned long long)*paddr, err); + return err; + } + + *paddr += console_mem_sz; + cxt->max_count++; + + return 0; +} + static int __init ramoops_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -287,35 +349,51 @@ static int __init ramoops_probe(struct platform_device *pdev) if (cxt->max_dump_count) goto fail_out; - if (!pdata->mem_size || !pdata->record_size) { - pr_err("The memory size and the record size must be " + if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size)) { + pr_err("The memory size and the record/console size must be " "non-zero\n"); goto fail_out; } pdata->mem_size = rounddown_pow_of_two(pdata->mem_size); pdata->record_size = rounddown_pow_of_two(pdata->record_size); + pdata->console_size = rounddown_pow_of_two(pdata->console_size); cxt->max_count = 0; cxt->count = 0; cxt->size = pdata->mem_size; cxt->phys_addr = pdata->mem_address; cxt->record_size = pdata->record_size; + cxt->console_size = pdata->console_size; cxt->dump_oops = pdata->dump_oops; cxt->ecc = pdata->ecc; paddr = cxt->phys_addr; - dump_mem_sz = cxt->size; + dump_mem_sz = cxt->size - cxt->console_size; err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz); - if (err) { + if (err) + goto fail_out; + + err = ramoops_init_cprz(dev, cxt, &paddr, cxt->console_size); + if (err) + goto fail_init_cprz; + + if (!cxt->max_count) { pr_err("memory size too small, minimum is %lu\n", - cxt->record_size); + cxt->console_size + cxt->record_size); goto fail_count; } cxt->pstore.data = cxt; - cxt->pstore.bufsize = cxt->przs[0]->buffer_size; + /* + * Console can handle any buffer size, so prefer dumps buffer + * size since usually it is smaller. + */ + if (cxt->przs) + cxt->pstore.bufsize = cxt->przs[0]->buffer_size; + else + cxt->pstore.bufsize = cxt->cprz->buffer_size; cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL); spin_lock_init(&cxt->pstore.buf_lock); if (!cxt->pstore.buf) { @@ -324,7 +402,7 @@ static int __init ramoops_probe(struct platform_device *pdev) } err = pstore_register(&cxt->pstore); - if (err || !cxt->max_count) { + if (err) { pr_err("registering with pstore failed\n"); goto fail_buf; } @@ -352,6 +430,8 @@ fail_clear: cxt->max_count = 0; cxt->max_dump_count = 0; fail_count: + ramoops_free_cprz(cxt); +fail_init_cprz: ramoops_free_przs(cxt); fail_out: return err; @@ -403,6 +483,7 @@ static int __init ramoops_init(void) dummy_data->mem_size = mem_size; dummy_data->mem_address = mem_address; dummy_data->record_size = record_size; + dummy_data->console_size = ramoops_console_size; dummy_data->dump_oops = dump_oops; dummy_data->ecc = ramoops_ecc; dummy = platform_create_bundle(&ramoops_driver, ramoops_probe, diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index 085199e..267248c 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -93,6 +93,7 @@ struct ramoops_platform_data { unsigned long mem_size; unsigned long mem_address; unsigned long record_size; + unsigned long console_size; int dump_oops; bool ecc; }; -- 1.7.9.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/