From patchwork Tue Jul 19 18:26:34 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Seiji Aguchi X-Patchwork-Id: 105504 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:4978:20e::2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id F3E12B6F00 for ; Wed, 20 Jul 2011 04:27:49 +1000 (EST) Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QjF10-0007uv-6h; Tue, 19 Jul 2011 18:27:30 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QjF0z-0005qb-Po; Tue, 19 Jul 2011 18:27:29 +0000 Received: from usindmx02.hds.com ([207.126.252.13]) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QjF0s-0005pw-2R; Tue, 19 Jul 2011 18:27:26 +0000 Received: from usindmail02.hds.com (usindmail02.hds.com [207.126.252.21]) by usindmx02.hds.com (8.14.1/8.14.1) with ESMTP id p6JIQb8S020383; Tue, 19 Jul 2011 14:26:37 -0400 (EDT) Received: from usindeht02.corp.hds.com (usindnetf5-vlan4float.corp.hds.com [10.74.12.196]) by usindmail02.hds.com (8.14.1/8.14.1) with ESMTP id p6JIQaLj024622; Tue, 19 Jul 2011 14:26:36 -0400 (EDT) Received: from USINDEVS01.corp.hds.com ([10.74.24.171]) by usindeht02.corp.hds.com ([10.74.24.185]) with mapi; Tue, 19 Jul 2011 14:26:36 -0400 From: Seiji Aguchi To: "kexec@lists.infradead.org" , "linux-kernel@vger.kernel.org" , "linux-mtd@lists.infradead.org" , "Eric W. Biederman" , Vivek Goyal , KOSAKI Motohiro , Americo Wang , Matthew Garrett , "tony.luck@intel.com" , Andrew Morton , Jarod Wilson , "hpa@zytor.com" , "dzickus@redhat.com" Date: Tue, 19 Jul 2011 14:26:34 -0400 Subject: [RFC][PATCH -mmotm 3/4] pstore: mtdoops support Thread-Topic: [RFC][PATCH -mmotm 3/4] pstore: mtdoops support Thread-Index: AcxGQPNfkgYolSqJQyKgeplzzN4MfQAAFV1g Message-ID: <5C4C569E8A4B9B42A84A977CF070A35B2C199C64C8@USINDEVS01.corp.hds.com> Accept-Language: ja-JP, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: acceptlanguage: ja-JP, en-US MIME-Version: 1.0 X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110719_142722_254767_F8E1DDDD X-CRM114-Status: GOOD ( 20.71 ) X-Spam-Score: -1.2 (-) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-1.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -1.2 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain Cc: "dle-develop@lists.sourceforge.net" , Satoru Moriya X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Hi, Pstore can support mtdoops with this patch. fs/pstore/platform.c - Add "reason" argument to pstore_dump() so that mtdoops can select its behaivor in accordance with each reason drivers/mtd/Kconfig - Add "depends on PSTORE" to CONFIG_MTD_OOPS drivers/mtd/mtdoops.c - Add pstore_info structure so that mtdoops can call pstore_register() - Remove kmsg_dump_unregister because pstore doesn't support unregister operation - Change printk() to DEBUG() in kexec path for avoiding dead lock due to logbuf_lock drivers/acpi/apei/erst.c - Add "reason" argument to erst_write() TODO: - I don't have any access to machine capable of Memory Technology Device. Please help to test my patch. - I haven't implemented reader/eraser callbacks supported by pstore. - If mtdoops users would like to unload module, pstore needs to support unregister operation. Signed-off-by: Seiji Aguchi --- drivers/acpi/apei/erst.c | 6 ++- drivers/mtd/Kconfig | 1 + drivers/mtd/mtdoops.c | 95 +++++++++++++++++++++++++++++++-------------- fs/pstore/platform.c | 5 +- include/linux/pstore.h | 3 +- 5 files changed, 75 insertions(+), 35 deletions(-) diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index e6cef8e..ee936b6 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -933,7 +933,8 @@ static int erst_open_pstore(struct pstore_info *psi); static int erst_close_pstore(struct pstore_info *psi); static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, struct timespec *time); -static u64 erst_writer(enum pstore_type_id type, size_t size); +static u64 erst_writer(enum pstore_type_id type, size_t size, + enum kmsg_dump_reason reason); static struct pstore_info erst_info = { .owner = THIS_MODULE, @@ -1037,7 +1038,8 @@ out: return (rc < 0) ? rc : (len - sizeof(*rcd)); } -static u64 erst_writer(enum pstore_type_id type, size_t size) +static u64 erst_writer(enum pstore_type_id type, size_t size, + enum kmsg_dump_reason reason) { struct cper_pstore_record *rcd = (struct cper_pstore_record *) (erst_info.buf - sizeof(*rcd)); diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index cc02e21..63a6e04 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -301,6 +301,7 @@ config SM_FTL config MTD_OOPS tristate "Log panic/oops to an MTD buffer" + depends on PSTORE help This enables panic and oops messages to be logged to a circular buffer in a flash partition where it can be read back at some diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 56eac4e..61b1120 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -32,6 +32,7 @@ #include #include #include +#include /* Maximum MTD partition size */ #define MTDOOPS_MAX_MTD_SIZE (8 * 1024 * 1024) @@ -54,6 +55,25 @@ module_param(dump_oops, int, 0600); MODULE_PARM_DESC(dump_oops, "set to 1 to dump oopses, 0 to only dump panics (default 1)"); +static unsigned long total_size; +static int mtdoops_open(struct pstore_info *psi); +static int mtdoops_close(struct pstore_info *psi); +static ssize_t mtdoops_reader(u64 *id, enum pstore_type_id *type, + struct timespec *time); +static u64 mtdoops_dumper(enum pstore_type_id type, size_t size, + enum kmsg_dump_reason reason); +static int mtdoops_eraser(u64 record_id); + +static struct pstore_info mtdoops_info = { + .owner = THIS_MODULE, + .name = "mtdoops", + .open = mtdoops_open, + .close = mtdoops_close, + .read = mtdoops_reader, + .write = mtdoops_dumper, + .erase = mtdoops_eraser +}; + static struct mtdoops_context { struct kmsg_dumper dump; @@ -229,8 +249,9 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic) record_size, &retlen, cxt->oops_buf); if (retlen != record_size || ret < 0) - printk(KERN_ERR "mtdoops: write failure at %ld (%td of %ld written), error %d\n", - cxt->nextpage * record_size, retlen, record_size, ret); + DEBUG(MTD_DEBUG_LEVEL3, "mtdoops: write failure at %ld (%td of " + "%ld written), error %d\n", cxt->nextpage * record_size, + retlen, record_size, ret); mark_page_used(cxt, cxt->nextpage); memset(cxt->oops_buf, 0xff, record_size); @@ -297,47 +318,62 @@ static void find_next_position(struct mtdoops_context *cxt) mtdoops_inc_counter(cxt); } -static void mtdoops_do_dump(struct kmsg_dumper *dumper, - enum kmsg_dump_reason reason, const char *s1, unsigned long l1, - const char *s2, unsigned long l2) +static int mtdoops_open(struct pstore_info *psi) +{ + return 0; +} + +static int mtdoops_close(struct pstore_info *psi) +{ + return 0; +} + +static ssize_t mtdoops_reader(u64 *id, enum pstore_type_id *type, + struct timespec *time) { - struct mtdoops_context *cxt = container_of(dumper, - struct mtdoops_context, dump); - unsigned long s1_start, s2_start; - unsigned long l1_cpy, l2_cpy; - char *dst; + return -EINVAL; +} + +static u64 mtdoops_dumper(enum pstore_type_id type, size_t size, + enum kmsg_dump_reason reason) +{ + struct mtdoops_context *cxt = &oops_cxt; if (reason != KMSG_DUMP_OOPS && - reason != KMSG_DUMP_PANIC) - return; + reason != KMSG_DUMP_PANIC && + reason != KMSG_DUMP_KEXEC) + return 0; /* Only dump oopses if dump_oops is set */ if (reason == KMSG_DUMP_OOPS && !dump_oops) - return; - - dst = cxt->oops_buf + MTDOOPS_HEADER_SIZE; /* Skip the header */ - l2_cpy = min(l2, record_size - MTDOOPS_HEADER_SIZE); - l1_cpy = min(l1, record_size - MTDOOPS_HEADER_SIZE - l2_cpy); - - s2_start = l2 - l2_cpy; - s1_start = l1 - l1_cpy; + return 0; - memcpy(dst, s1 + s1_start, l1_cpy); - memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy); + if (total_size >= record_size) + return 0; /* Panics must be written immediately */ if (reason != KMSG_DUMP_OOPS) { if (!cxt->mtd->panic_write) - printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n"); - else + DEBUG(MTD_DEBUG_LEVEL3, "mtdoops: Cannot write from " + "panic without panic_write\n"); + else { mtdoops_write(cxt, 1); - return; + total_size = total_size + size + MTDOOPS_HEADER_SIZE; + } + return 0; } /* For other cases, schedule work to write it "nicely" */ schedule_work(&cxt->work_write); + return 0; } +static int mtdoops_eraser(u64 record_id) +{ + return 0; +} + + static void mtdoops_notify_add(struct mtd_info *mtd) { struct mtdoops_context *cxt = &oops_cxt; @@ -374,8 +410,10 @@ static void mtdoops_notify_add(struct mtd_info *mtd) return; } - cxt->dump.dump = mtdoops_do_dump; - err = kmsg_dump_register(&cxt->dump); + mutex_init(&mtdoops_info.buf_mutex); + mtdoops_info.buf = cxt->oops_buf + MTDOOPS_HEADER_SIZE; + mtdoops_info.bufsize = record_size - MTDOOPS_HEADER_SIZE; + err = pstore_register(&mtdoops_info); if (err) { printk(KERN_ERR "mtdoops: registering kmsg dumper failed, error %d\n", err); vfree(cxt->oops_page_used); @@ -396,9 +434,6 @@ static void mtdoops_notify_remove(struct mtd_info *mtd) if (mtd->index != cxt->mtd_index || cxt->mtd_index < 0) return; - if (kmsg_dump_unregister(&cxt->dump) < 0) - printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n"); - cxt->mtd = NULL; flush_work_sync(&cxt->work_erase); flush_work_sync(&cxt->work_write); diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 061911c..cd42b4e 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -105,7 +105,8 @@ static void pstore_dump(struct kmsg_dumper *dumper, memcpy(dst, s1 + s1_start, l1_cpy); memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy); - id = psinfo->write(PSTORE_TYPE_DMESG, hsize + l1_cpy + l2_cpy); + id = psinfo->write(PSTORE_TYPE_DMESG, hsize + l1_cpy + l2_cpy, + reason); if (reason == KMSG_DUMP_OOPS && pstore_is_mounted()) pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, psinfo->buf, hsize + l1_cpy + l2_cpy, @@ -220,7 +221,7 @@ int pstore_write(enum pstore_type_id type, char *buf, size_t size) mutex_lock(&psinfo->buf_mutex); memcpy(psinfo->buf, buf, size); - id = psinfo->write(type, size); + id = psinfo->write(type, size, 0); if (pstore_is_mounted()) pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, psinfo->buf, size, CURRENT_TIME, psinfo->erase); diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 5cf008d..47b974f 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -41,7 +41,8 @@ struct pstore_info { int (*close)(struct pstore_info *psi); ssize_t (*read)(u64 *id, enum pstore_type_id *type, struct timespec *time); - u64 (*write)(enum pstore_type_id type, size_t size); + u64 (*write)(enum pstore_type_id type, size_t size, + enum kmsg_dump_reason reason); int (*erase)(u64 id); };