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 <[email protected]>

---
 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 <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
 #include <linux/kmsg_dump.h>
+#include <linux/pstore.h>
 
 /* 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);
 };
 
-- 
1.7.1


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

Reply via email to