From patchwork Fri May 18 22:25:43 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Vorontsov X-Patchwork-Id: 8825 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 3144223EB5 for ; Fri, 18 May 2012 22:27:15 +0000 (UTC) Received: from mail-gg0-f180.google.com (mail-gg0-f180.google.com [209.85.161.180]) by fiordland.canonical.com (Postfix) with ESMTP id D854DA183D8 for ; Fri, 18 May 2012 22:27:14 +0000 (UTC) Received: by mail-gg0-f180.google.com with SMTP id f1so4151034ggn.11 for ; Fri, 18 May 2012 15:27:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:date:from :to:cc:subject:message-id:references:mime-version:content-type :content-disposition:in-reply-to:user-agent:x-gm-message-state; bh=KBN5CBTT/4ALuyq7z9B8SueUA2nohDmkfdY+EyVkRcA=; b=DIHZK5uDZ16TPu+GUaAf0TOZqDgLSanyN9aZEYC+A3df56kw3qV7+b21x25UJecXnb zzc/z49AuLUsBZc5k/wmyygXDz+SpZuidTnlkLA63gDu73wxqcQ3pUcTlwGVZjj7noml BjQP6ZSianp54Y0k5xhnoIQHHvajOdAkQ0QWf2YCoGQFHcIvPWqSmm+faKXLloIfyEQ2 ahUAQcOR2vYw/lwsJfrnEjgtRWDu5e4x53FuxTUcNJZ2dMYanrs6NfeVa/NCqiDu+BIn qXkDBNsHUdmoU+v75Kb8Ih/uWV/dz+2rYxTUFS7k+K7nE9RkQZ27GgcQG58i8b0jHymn uY0w== Received: by 10.50.222.202 with SMTP id qo10mr2106270igc.0.1337380034175; Fri, 18 May 2012 15:27:14 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.35.72 with SMTP id o8csp135306ibd; Fri, 18 May 2012 15:27:13 -0700 (PDT) Received: by 10.68.221.35 with SMTP id qb3mr43201100pbc.136.1337380033406; Fri, 18 May 2012 15:27:13 -0700 (PDT) Received: from mail-pb0-f50.google.com (mail-pb0-f50.google.com [209.85.160.50]) by mx.google.com with ESMTPS id qa10si17675425pbb.174.2012.05.18.15.27.13 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 18 May 2012 15:27:13 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.160.50 is neither permitted nor denied by best guess record for domain of anton.vorontsov@linaro.org) client-ip=209.85.160.50; Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.160.50 is neither permitted nor denied by best guess record for domain of anton.vorontsov@linaro.org) smtp.mail=anton.vorontsov@linaro.org Received: by mail-pb0-f50.google.com with SMTP id rr4so5393549pbb.37 for ; Fri, 18 May 2012 15:27:13 -0700 (PDT) Received: by 10.68.219.41 with SMTP id pl9mr43150880pbc.61.1337380033075; Fri, 18 May 2012 15:27:13 -0700 (PDT) Received: from localhost (c-71-204-165-222.hsd1.ca.comcast.net. [71.204.165.222]) by mx.google.com with ESMTPS id gl5sm13319211pbc.58.2012.05.18.15.27.10 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 18 May 2012 15:27:12 -0700 (PDT) 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-Disposition: inline In-Reply-To: <20120518222314.GA9425@lizard> User-Agent: Mutt/1.5.21 (2010-09-15) X-Gm-Message-State: ALoCoQlmVIkX7pH63uqv/9zsgyPXCxjTlxfRdMumFgu5ZvFhU2G4tuFkKRs1AgpGuCvjX60Peus6 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; };