All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 0/5]: mtdoops: fixes and improvements
@ 2009-10-15  7:40 Simon Kagstrom
  2009-10-15  7:47 ` [PATCH v7 1/5]: mtdoops: avoid erasing already empty areas Simon Kagstrom
                   ` (5 more replies)
  0 siblings, 6 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-15  7:40 UTC (permalink / raw)
  To: Artem Bityutskiy, linux-mtd, David Woodhouse

Hi!

(I'm taking the most of the discussion back to the mtd-list since most
of it is now pure mtdoops stuff).

Here are a couple of patches to mtdoops which I've been working on for
a while and which were recently discussed on the MTD list. They are
applied on top of Artems tree,

  http://git.infradead.org/users/dedekind/l2-mtd-2.6.git

which apart from the mainline tree contains a panic fix from Aaro and
Artems mtdoops style cleanup patch.


Now, I'd like to warn sensitive readers that patch 5 *does* contain work
queue elements. However, I believe there is a good reason for this: The
mtd->write call is not good to call while oopsing, and mtd->panic_write
is sort of a last resort. Now, if we panic anyhow, mtd->panic_write
will be called, so the oops will still be written and the scheduled
work won't run anyway.


The patches are:

1. Avoid erasing already empty areas (the area would be erased at each
   module load otherwise)

2. Keep track of mtdoops page cleanliness in an array. This allows
   mtdoops_inc_counter to be called during panic (which fails in my
   case with the current code in mtd->read, although I believe this is
   MTD-driver dependent).

3. Make page size configurable to support longer messages. Mainly
   needed for patch 4, but also allows longer messages to be stored
   during panics (when the next oops area cannot be erased).

4. (kernel/printk.c) Add a kmsg_dumper as per Linus suggestion which
   includes a dump_kmsg function which dumps the kernel log buffer to
   registered devices.

5. Refactor mtdoops as a kmsg_dumper device instead of a console device.

ChangeLog:

v2:
  * Patches have been reordered to keep the least controversial (?) first.
  * Implement Artems suggestion to keep cleanliness in an array
  * Use Aaros patch to fix the panic_on_oops problem

v3:
  * Correct checkpatch issues

v4: Review corrections
  * Rebase on top of "[PATCH] mtd: mtdoops: several minor cleanups"
  * Patch 1 has been added
  * Use 1 bit per oops page, and rename clean/dirty unused/used
  * Don't initialize oops_page_dirty (it's a global structure anyway so
    it will be cleared together with the rest of BSS)
  * Rename mtdoops_page_size record_size (although only for the page
    size setting)

v5: Corrections after panic_on_oops discussion
  * Add dump_device
  * Refactor mtdoops as a dump device.

v6: More corrections (panic_on_oops and Anders Grafström, my room-mate at work)
  * Patches 2-5 modified
  * Use set_bit/clear_bit primitives in patch 2
  * Set permissions for mtdoops arguments correct in patch 3 and 5
  * Rename files and structures after Linus suggestions in patch 4
  * Correct output under some conditions in patch 5

v7: Even more corrections:
  * Patches 4-5 modified
  * Remove the priv pointer from the kmsg_dumper structure
  * Add Kconfig description of how to use mtdoops
  * Fix kfree bug

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v7 1/5]: mtdoops: avoid erasing already empty areas
  2009-10-15  7:40 [PATCH v7 0/5]: mtdoops: fixes and improvements Simon Kagstrom
@ 2009-10-15  7:47 ` Simon Kagstrom
  2009-10-23  3:57   ` Artem Bityutskiy
  2009-10-15  7:47 ` [PATCH v7 2/5]: mtdoops: Keep track of used/unused mtdoops pages in an array Simon Kagstrom
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-15  7:47 UTC (permalink / raw)
  To: Artem Bityutskiy, linux-mtd; +Cc: David Woodhouse

After having scanned the entire mtdoops area, mtdoops will erase it if
there are no mtdoops headers in it. However, empty and already erased
areas (i.e., without mtdoops headers) will therefore also be erased at
each startup.

This patch counts the number of unclean pages (neither empty nor with
the mtdoops header) and only erases if no headers are found and the area
is still unclean.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
---
 drivers/mtd/mtdoops.c |   18 ++++++++++++++----
 1 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 18c6c96..c785e1a 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -225,7 +225,7 @@ static void mtdoops_workfunc_write(struct work_struct *work)
 static void find_next_position(struct mtdoops_context *cxt)
 {
 	struct mtd_info *mtd = cxt->mtd;
-	int ret, page, maxpos = 0;
+	int ret, page, maxpos = 0, unclean_pages = 0;
 	u32 count[2], maxcount = 0xffffffff;
 	size_t retlen;
 
@@ -237,10 +237,13 @@ static void find_next_position(struct mtdoops_context *cxt)
 			continue;
 		}
 
-		if (count[1] != MTDOOPS_KERNMSG_MAGIC)
-			continue;
 		if (count[0] == 0xffffffff)
 			continue;
+		if (count[1] != MTDOOPS_KERNMSG_MAGIC) {
+			/* Page is neither clean nor empty */
+			unclean_pages++;
+			continue;
+		}
 		if (maxcount == 0xffffffff) {
 			maxcount = count[0];
 			maxpos = page;
@@ -259,7 +262,14 @@ static void find_next_position(struct mtdoops_context *cxt)
 	if (maxcount == 0xffffffff) {
 		cxt->nextpage = 0;
 		cxt->nextcount = 1;
-		schedule_work(&cxt->work_erase);
+		if (unclean_pages != 0) {
+			printk(KERN_INFO "mtdoops: cleaning area\n");
+			schedule_work(&cxt->work_erase);
+		} else {
+			printk(KERN_DEBUG "mtdoops: ready %d, %d (clean)\n",
+			       cxt->nextpage, cxt->nextcount);
+			cxt->ready = 1;
+		}
 		return;
 	}
 
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v7 2/5]: mtdoops: Keep track of used/unused mtdoops pages in an array
  2009-10-15  7:40 [PATCH v7 0/5]: mtdoops: fixes and improvements Simon Kagstrom
  2009-10-15  7:47 ` [PATCH v7 1/5]: mtdoops: avoid erasing already empty areas Simon Kagstrom
@ 2009-10-15  7:47 ` Simon Kagstrom
  2009-10-23  4:08   ` Artem Bityutskiy
  2009-10-15  7:47 ` [PATCH v7 3/5]: mtdoops: Make page (record) size configurable Simon Kagstrom
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-15  7:47 UTC (permalink / raw)
  To: Artem Bityutskiy, linux-mtd; +Cc: David Woodhouse

This patch makes mtdoops keep track of used/unused pages in an array
instead of scanning the flash after a write. The advantage with this
approach is that it avoids calling mtd->read on a panic, which is not
possible for all mtd drivers.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
---
 drivers/mtd/mtdoops.c |   62 ++++++++++++++++++++++++++++++++++--------------
 1 files changed, 44 insertions(+), 18 deletions(-)

diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index c785e1a..08627c2 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -44,6 +44,7 @@ static struct mtdoops_context {
 	int oops_pages;
 	int nextpage;
 	int nextcount;
+	unsigned long *oops_page_used;
 	char *name;
 
 	void *oops_buf;
@@ -54,18 +55,38 @@ static struct mtdoops_context {
 	int writecount;
 } oops_cxt;
 
+static void mark_page_used(struct mtdoops_context *cxt, int page)
+{
+	set_bit(page, cxt->oops_page_used);
+}
+
+static void mark_page_unused(struct mtdoops_context *cxt, int page)
+{
+	clear_bit(page, cxt->oops_page_used);
+}
+
+static int page_is_used(struct mtdoops_context *cxt, int page)
+{
+	return test_bit(page, cxt->oops_page_used);
+}
+
 static void mtdoops_erase_callback(struct erase_info *done)
 {
 	wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
 	wake_up(wait_q);
 }
 
-static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
+static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
 {
+	struct mtd_info *mtd = cxt->mtd;
+	u32 start_page_offset = mtd_div_by_eb(offset, mtd) * mtd->erasesize;
+	u32 start_page = start_page_offset / OOPS_PAGE_SIZE;
+	u32 erase_pages = mtd->erasesize / OOPS_PAGE_SIZE;
 	struct erase_info erase;
 	DECLARE_WAITQUEUE(wait, current);
 	wait_queue_head_t wait_q;
 	int ret;
+	int page;
 
 	init_waitqueue_head(&wait_q);
 	erase.mtd = mtd;
@@ -90,16 +111,15 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
 	schedule();  /* Wait for erase to finish. */
 	remove_wait_queue(&wait_q, &wait);
 
+	/* Mark pages as unused */
+	for (page = start_page; page < start_page + erase_pages; page++)
+		mark_page_unused(cxt, page);
+
 	return 0;
 }
 
 static void mtdoops_inc_counter(struct mtdoops_context *cxt)
 {
-	struct mtd_info *mtd = cxt->mtd;
-	size_t retlen;
-	u32 count;
-	int ret;
-
 	cxt->nextpage++;
 	if (cxt->nextpage >= cxt->oops_pages)
 		cxt->nextpage = 0;
@@ -107,17 +127,7 @@ static void mtdoops_inc_counter(struct mtdoops_context *cxt)
 	if (cxt->nextcount == 0xffffffff)
 		cxt->nextcount = 0;
 
-	ret = mtd->read(mtd, cxt->nextpage * OOPS_PAGE_SIZE, 4,
-			&retlen, (u_char *) &count);
-	if (retlen != 4 || (ret < 0 && ret != -EUCLEAN)) {
-		printk(KERN_ERR "mtdoops: read failure at %d (%td of 4 read), err %d\n",
-		       cxt->nextpage * OOPS_PAGE_SIZE, retlen, ret);
-		schedule_work(&cxt->work_erase);
-		return;
-	}
-
-	/* See if we need to erase the next block */
-	if (count != 0xffffffff) {
+	if (page_is_used(cxt, cxt->nextpage)) {
 		schedule_work(&cxt->work_erase);
 		return;
 	}
@@ -168,7 +178,7 @@ badblock:
 	}
 
 	for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
-		ret = mtdoops_erase_block(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+		ret = mtdoops_erase_block(cxt, cxt->nextpage * OOPS_PAGE_SIZE);
 
 	if (ret >= 0) {
 		printk(KERN_DEBUG "mtdoops: ready %d, %d\n",
@@ -209,6 +219,7 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 	if (retlen != OOPS_PAGE_SIZE || ret < 0)
 		printk(KERN_ERR "mtdoops: write failure at %d (%td of %d written), error %d\n",
 		       cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret);
+	mark_page_used(cxt, cxt->nextpage);
 
 	mtdoops_inc_counter(cxt);
 }
@@ -230,6 +241,8 @@ static void find_next_position(struct mtdoops_context *cxt)
 	size_t retlen;
 
 	for (page = 0; page < cxt->oops_pages; page++) {
+		/* Assume the page is used */
+		mark_page_used(cxt, page);
 		ret = mtd->read(mtd, page * OOPS_PAGE_SIZE, 8, &retlen, (u_char *) &count[0]);
 		if (retlen != 8 || (ret < 0 && ret != -EUCLEAN)) {
 			printk(KERN_ERR "mtdoops: read failure at %d (%td of 8 read), err %d\n",
@@ -237,6 +250,8 @@ static void find_next_position(struct mtdoops_context *cxt)
 			continue;
 		}
 
+		if (count[0] == 0xffffffff && count[1] == 0xffffffff)
+			mark_page_unused(cxt, page);
 		if (count[0] == 0xffffffff)
 			continue;
 		if (count[1] != MTDOOPS_KERNMSG_MAGIC) {
@@ -283,6 +298,9 @@ static void find_next_position(struct mtdoops_context *cxt)
 static void mtdoops_notify_add(struct mtd_info *mtd)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
+	u64 mtdoops_pages = mtd->size;
+
+	do_div(mtdoops_pages, OOPS_PAGE_SIZE);
 
 	if (cxt->name && !strcmp(mtd->name, cxt->name))
 		cxt->mtd_index = mtd->index;
@@ -302,6 +320,13 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		return;
 	}
 
+	/* oops_page_used is a bit field */
+	cxt->oops_page_used = vmalloc(DIV_ROUND_UP(mtdoops_pages,
+			BITS_PER_LONG));
+	if (!cxt->oops_page_used) {
+		printk(KERN_ERR "Could not allocate page array\n");
+		return;
+	}
 	cxt->mtd = mtd;
 	if (mtd->size > INT_MAX)
 		cxt->oops_pages = INT_MAX / OOPS_PAGE_SIZE;
@@ -454,6 +479,7 @@ static void __exit mtdoops_console_exit(void)
 	unregister_console(&mtdoops_console);
 	kfree(cxt->name);
 	vfree(cxt->oops_buf);
+	vfree(cxt->oops_page_used);
 }
 
 
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v7 3/5]: mtdoops: Make page (record) size configurable
  2009-10-15  7:40 [PATCH v7 0/5]: mtdoops: fixes and improvements Simon Kagstrom
  2009-10-15  7:47 ` [PATCH v7 1/5]: mtdoops: avoid erasing already empty areas Simon Kagstrom
  2009-10-15  7:47 ` [PATCH v7 2/5]: mtdoops: Keep track of used/unused mtdoops pages in an array Simon Kagstrom
@ 2009-10-15  7:47 ` Simon Kagstrom
  2009-10-23  4:13   ` Artem Bityutskiy
  2009-10-15  7:48   ` Simon Kagstrom
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-15  7:47 UTC (permalink / raw)
  To: Artem Bityutskiy, linux-mtd; +Cc: David Woodhouse

The main justification for this is to allow catching long messages
during a panic, where the top part might otherwise be lost since moving
to the next block can require a flash erase.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
---
 drivers/mtd/mtdoops.c |   76 ++++++++++++++++++++++++++++--------------------
 1 files changed, 44 insertions(+), 32 deletions(-)

diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 08627c2..2870a11 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -34,7 +34,11 @@
 #include <linux/mtd/mtd.h>
 
 #define MTDOOPS_KERNMSG_MAGIC 0x5d005d00
-#define OOPS_PAGE_SIZE 4096
+
+static unsigned long record_size = 4096;
+module_param(record_size, ulong, 0400);
+MODULE_PARM_DESC(record_size,
+		"record size for MTD OOPS pages in bytes (default 4096)");
 
 static struct mtdoops_context {
 	int mtd_index;
@@ -80,8 +84,8 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
 {
 	struct mtd_info *mtd = cxt->mtd;
 	u32 start_page_offset = mtd_div_by_eb(offset, mtd) * mtd->erasesize;
-	u32 start_page = start_page_offset / OOPS_PAGE_SIZE;
-	u32 erase_pages = mtd->erasesize / OOPS_PAGE_SIZE;
+	u32 start_page = start_page_offset / record_size;
+	u32 erase_pages = mtd->erasesize / record_size;
 	struct erase_info erase;
 	DECLARE_WAITQUEUE(wait, current);
 	wait_queue_head_t wait_q;
@@ -149,15 +153,15 @@ static void mtdoops_workfunc_erase(struct work_struct *work)
 	if (!mtd)
 		return;
 
-	mod = (cxt->nextpage * OOPS_PAGE_SIZE) % mtd->erasesize;
+	mod = (cxt->nextpage * record_size) % mtd->erasesize;
 	if (mod != 0) {
-		cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / OOPS_PAGE_SIZE);
+		cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / record_size);
 		if (cxt->nextpage >= cxt->oops_pages)
 			cxt->nextpage = 0;
 	}
 
 	while (mtd->block_isbad) {
-		ret = mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+		ret = mtd->block_isbad(mtd, cxt->nextpage * record_size);
 		if (!ret)
 			break;
 		if (ret < 0) {
@@ -165,20 +169,20 @@ static void mtdoops_workfunc_erase(struct work_struct *work)
 			return;
 		}
 badblock:
-		printk(KERN_WARNING "mtdoops: bad block at %08x\n",
-		       cxt->nextpage * OOPS_PAGE_SIZE);
+		printk(KERN_WARNING "mtdoops: bad block at %08lx\n",
+		       cxt->nextpage * record_size);
 		i++;
-		cxt->nextpage = cxt->nextpage + (mtd->erasesize / OOPS_PAGE_SIZE);
+		cxt->nextpage = cxt->nextpage + (mtd->erasesize / record_size);
 		if (cxt->nextpage >= cxt->oops_pages)
 			cxt->nextpage = 0;
-		if (i == cxt->oops_pages / (mtd->erasesize / OOPS_PAGE_SIZE)) {
+		if (i == cxt->oops_pages / (mtd->erasesize / record_size)) {
 			printk(KERN_ERR "mtdoops: all blocks bad!\n");
 			return;
 		}
 	}
 
 	for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
-		ret = mtdoops_erase_block(cxt, cxt->nextpage * OOPS_PAGE_SIZE);
+		ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size);
 
 	if (ret >= 0) {
 		printk(KERN_DEBUG "mtdoops: ready %d, %d\n",
@@ -188,7 +192,7 @@ badblock:
 	}
 
 	if (mtd->block_markbad && ret == -EIO) {
-		ret = mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+		ret = mtd->block_markbad(mtd, cxt->nextpage * record_size);
 		if (ret < 0) {
 			printk(KERN_ERR "mtdoops: block_markbad failed, aborting\n");
 			return;
@@ -203,22 +207,22 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 	size_t retlen;
 	int ret;
 
-	if (cxt->writecount < OOPS_PAGE_SIZE)
+	if (cxt->writecount < record_size)
 		memset(cxt->oops_buf + cxt->writecount, 0xff,
-					OOPS_PAGE_SIZE - cxt->writecount);
+					record_size - cxt->writecount);
 
 	if (panic)
-		ret = mtd->panic_write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
-					OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+		ret = mtd->panic_write(mtd, cxt->nextpage * record_size,
+					record_size, &retlen, cxt->oops_buf);
 	else
-		ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
-					OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+		ret = mtd->write(mtd, cxt->nextpage * record_size,
+					record_size, &retlen, cxt->oops_buf);
 
 	cxt->writecount = 0;
 
-	if (retlen != OOPS_PAGE_SIZE || ret < 0)
-		printk(KERN_ERR "mtdoops: write failure at %d (%td of %d written), error %d\n",
-		       cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret);
+	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);
 	mark_page_used(cxt, cxt->nextpage);
 
 	mtdoops_inc_counter(cxt);
@@ -243,10 +247,10 @@ static void find_next_position(struct mtdoops_context *cxt)
 	for (page = 0; page < cxt->oops_pages; page++) {
 		/* Assume the page is used */
 		mark_page_used(cxt, page);
-		ret = mtd->read(mtd, page * OOPS_PAGE_SIZE, 8, &retlen, (u_char *) &count[0]);
+		ret = mtd->read(mtd, page * record_size, 8, &retlen, (u_char *) &count[0]);
 		if (retlen != 8 || (ret < 0 && ret != -EUCLEAN)) {
-			printk(KERN_ERR "mtdoops: read failure at %d (%td of 8 read), err %d\n",
-			       page * OOPS_PAGE_SIZE, retlen, ret);
+			printk(KERN_ERR "mtdoops: read failure at %ld (%td of 8 read), err %d\n",
+			       page * record_size, retlen, ret);
 			continue;
 		}
 
@@ -300,7 +304,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 	struct mtdoops_context *cxt = &oops_cxt;
 	u64 mtdoops_pages = mtd->size;
 
-	do_div(mtdoops_pages, OOPS_PAGE_SIZE);
+	do_div(mtdoops_pages, record_size);
 
 	if (cxt->name && !strcmp(mtd->name, cxt->name))
 		cxt->mtd_index = mtd->index;
@@ -314,7 +318,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		return;
 	}
 
-	if (mtd->erasesize < OOPS_PAGE_SIZE) {
+	if (mtd->erasesize < record_size) {
 		printk(KERN_ERR "mtdoops: eraseblock size of MTD partition %d too small\n",
 		       mtd->index);
 		return;
@@ -329,9 +333,9 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 	}
 	cxt->mtd = mtd;
 	if (mtd->size > INT_MAX)
-		cxt->oops_pages = INT_MAX / OOPS_PAGE_SIZE;
+		cxt->oops_pages = INT_MAX / record_size;
 	else
-		cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE;
+		cxt->oops_pages = (int)mtd->size / record_size;
 
 	find_next_position(cxt);
 
@@ -408,15 +412,15 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
 		cxt->writecount = 8;
 	}
 
-	if (count + cxt->writecount > OOPS_PAGE_SIZE)
-		count = OOPS_PAGE_SIZE - cxt->writecount;
+	if (count + cxt->writecount > record_size)
+		count = record_size - cxt->writecount;
 
 	memcpy(cxt->oops_buf + cxt->writecount, s, count);
 	cxt->writecount += count;
 
 	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
 
-	if (cxt->writecount == OOPS_PAGE_SIZE)
+	if (cxt->writecount == record_size)
 		mtdoops_console_sync();
 }
 
@@ -455,8 +459,16 @@ static int __init mtdoops_console_init(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
 
+	if ((record_size & 4095) != 0) {
+		printk(KERN_ERR "mtdoops: record_size must be a multiple of 4096\n");
+		return -EINVAL;
+	}
+	if (record_size < 4096) {
+		printk(KERN_ERR "mtdoops: record_size must be over 4096 bytes\n");
+		return -EINVAL;
+	}
 	cxt->mtd_index = -1;
-	cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE);
+	cxt->oops_buf = vmalloc(record_size);
 	if (!cxt->oops_buf) {
 		printk(KERN_ERR "mtdoops: failed to allocate buffer workspace\n");
 		return -ENOMEM;
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v7 4/5]: core: Add kernel message dumper to call on oopses and panics
  2009-10-15  7:40 [PATCH v7 0/5]: mtdoops: fixes and improvements Simon Kagstrom
@ 2009-10-15  7:48   ` Simon Kagstrom
  2009-10-15  7:47 ` [PATCH v7 2/5]: mtdoops: Keep track of used/unused mtdoops pages in an array Simon Kagstrom
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-15  7:48 UTC (permalink / raw)
  To: Linus Torvalds, linux-mtd
  Cc: Artem Bityutskiy, David Woodhouse, Ingo Molnar, Andrew Morton,
	LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

The core functionality is implemented as per Linus suggestion from

  http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html

(with the dump_kmsg implementation by Linus). A struct kmsg_dumper has
been added which contains a callback to dump the kernel log buffers on
crashes. The dump_kmsg function gets called from oops_exit() and panic()
and invokes this callbacks with the crash reason.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
---
ChangeLog:

 * (The other patches are sent only to linux-mtd since they are really
   just mtdoops-specific now)
 * (Linus) remove the priv pointer in the structure and
   let users determine the address of their own structure
   with container_of

 include/linux/kmsg_dump.h |   36 +++++++++++++++
 kernel/panic.c            |    3 +
 kernel/printk.c           |  104 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/kmsg_dump.h

diff --git a/include/linux/kmsg_dump.h b/include/linux/kmsg_dump.h
new file mode 100644
index 0000000..d7c9a4c
--- /dev/null
+++ b/include/linux/kmsg_dump.h
@@ -0,0 +1,36 @@
+/*
+ * linux/include/kmsg_dump.h
+ *
+ * Copyright (C) 2009 Net Insight AB
+ *
+ * Author: Simon Kagstrom <simon.kagstrom@netinsight.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+#ifndef _LINUX_KMSG_DUMP_H
+#define _LINUX_KMSG_DUMP_H
+
+#include <linux/list.h>
+
+enum kmsg_dump_reason {
+	kmsg_dump_oops,
+	kmsg_dump_panic,
+};
+
+struct kmsg_dumper {
+	void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
+			const char *s1, unsigned long l1,
+			const char *s2, unsigned long l2);
+	struct list_head list;
+	int registered;
+};
+
+void dump_kmsg(enum kmsg_dump_reason reason);
+
+int register_kmsg_dumper(struct kmsg_dumper *dumper);
+
+void unregister_kmsg_dumper(struct kmsg_dumper *dumper);
+
+#endif /* _LINUX_DUMP_DEVICE_H */
diff --git a/kernel/panic.c b/kernel/panic.c
index c0b33b8..3a5a93f 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -10,6 +10,7 @@
  */
 #include <linux/debug_locks.h>
 #include <linux/interrupt.h>
+#include <linux/kmsg_dump.h>
 #include <linux/kallsyms.h>
 #include <linux/notifier.h>
 #include <linux/module.h>
@@ -76,6 +77,7 @@ NORET_TYPE void panic(const char * fmt, ...)
 	dump_stack();
 #endif
 
+	dump_kmsg(kmsg_dump_panic);
 	/*
 	 * If we have crashed and we have a crash kernel loaded let it handle
 	 * everything else.
@@ -341,6 +343,7 @@ void oops_exit(void)
 {
 	do_oops_enter_exit();
 	print_oops_end_marker();
+	dump_kmsg(kmsg_dump_oops);
 }
 
 #ifdef WANT_WARN_ON_SLOWPATH
diff --git a/kernel/printk.c b/kernel/printk.c
index f38b07f..9c4d9cb 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -33,6 +33,8 @@
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
+#include <linux/kmsg_dump.h>
+#include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
 
@@ -1405,3 +1407,105 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 }
 EXPORT_SYMBOL(printk_timed_ratelimit);
 #endif
+
+static LIST_HEAD(dump_list);
+static DEFINE_SPINLOCK(dump_list_lock);
+
+/**
+ *	register_dump_device - register a kernel log dumper.
+ *	@dump: pointer to the dump structure
+ *	@priv: private data for the structure
+ *
+ *	Adds a kernel log dumper to the system. The dump callback in the
+ *	structure will be called when the kernel oopses or panics and must be
+ *	set. Returns zero on success and -EINVAL or -EBUSY otherwise.
+ */
+int register_kmsg_dumper(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	/* The dump callback needs to be set */
+	if (!dumper->dump)
+		return -EINVAL;
+
+	/* Don't allow registering multiple times */
+	if (dumper->registered)
+		return -EBUSY;
+
+	dumper->registered = 1;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	list_add(&dumper->list, &dump_list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL(register_kmsg_dumper);
+
+/**
+ *	unregister_dump_device - unregister a dumpdevice.
+ *	@dump: pointer to the dump structure
+ *
+ *	Removes a dump device from the system.
+ */
+void unregister_kmsg_dumper(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	list_del(&dumper->list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+}
+EXPORT_SYMBOL(unregister_kmsg_dumper);
+
+static const char *kmsg_reasons[] = {
+	[kmsg_dump_oops]	= "oops",
+	[kmsg_dump_panic]	= "panic",
+};
+
+static const char *kmsg_to_str(enum kmsg_dump_reason reason)
+{
+	if (reason > ARRAY_SIZE(kmsg_reasons) || reason < 0)
+		return "unknown";
+
+	return kmsg_reasons[reason];
+}
+
+/**
+ *	dump_kmsg - dump kernel log to kernel message dumpers.
+ *	@reason: the reason (oops, panic etc) for dumping
+ *
+ *	Iterate through each of the dump devices and call the oops/panic
+ *	callbacks with the log buffer.
+ */
+void dump_kmsg(enum kmsg_dump_reason reason)
+{
+	unsigned long len = ACCESS_ONCE(log_end);
+	struct kmsg_dumper *dumper;
+	const char *s1, *s2;
+	unsigned long l1, l2;
+
+	s1 = "";
+	l1 = 0;
+	s2 = log_buf;
+	l2 = len;
+
+	/* Have we rotated around the circular buffer? */
+	if (len > log_buf_len) {
+		unsigned long pos = len & LOG_BUF_MASK;
+
+		s1 = log_buf + pos;
+		l1 = log_buf_len - pos;
+
+		s2 = log_buf;
+		l2 = pos;
+	}
+
+	if (!spin_trylock(&dump_list_lock)) {
+		printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n",
+				kmsg_to_str(reason));
+		return;
+	}
+	list_for_each_entry(dumper, &dump_list, list)
+		dumper->dump(dumper, reason, s1, l1, s2, l2);
+	spin_unlock(&dump_list_lock);
+}
-- 
1.6.0.4


^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v7 4/5]: core: Add kernel message dumper to call on oopses and panics
@ 2009-10-15  7:48   ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-15  7:48 UTC (permalink / raw)
  To: Linus Torvalds, linux-mtd
  Cc: Artem Bityutskiy, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Ingo Molnar, David Woodhouse, Andrew Morton, Alan Cox

The core functionality is implemented as per Linus suggestion from

  http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html

(with the dump_kmsg implementation by Linus). A struct kmsg_dumper has
been added which contains a callback to dump the kernel log buffers on
crashes. The dump_kmsg function gets called from oops_exit() and panic()
and invokes this callbacks with the crash reason.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
---
ChangeLog:

 * (The other patches are sent only to linux-mtd since they are really
   just mtdoops-specific now)
 * (Linus) remove the priv pointer in the structure and
   let users determine the address of their own structure
   with container_of

 include/linux/kmsg_dump.h |   36 +++++++++++++++
 kernel/panic.c            |    3 +
 kernel/printk.c           |  104 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/kmsg_dump.h

diff --git a/include/linux/kmsg_dump.h b/include/linux/kmsg_dump.h
new file mode 100644
index 0000000..d7c9a4c
--- /dev/null
+++ b/include/linux/kmsg_dump.h
@@ -0,0 +1,36 @@
+/*
+ * linux/include/kmsg_dump.h
+ *
+ * Copyright (C) 2009 Net Insight AB
+ *
+ * Author: Simon Kagstrom <simon.kagstrom@netinsight.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+#ifndef _LINUX_KMSG_DUMP_H
+#define _LINUX_KMSG_DUMP_H
+
+#include <linux/list.h>
+
+enum kmsg_dump_reason {
+	kmsg_dump_oops,
+	kmsg_dump_panic,
+};
+
+struct kmsg_dumper {
+	void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
+			const char *s1, unsigned long l1,
+			const char *s2, unsigned long l2);
+	struct list_head list;
+	int registered;
+};
+
+void dump_kmsg(enum kmsg_dump_reason reason);
+
+int register_kmsg_dumper(struct kmsg_dumper *dumper);
+
+void unregister_kmsg_dumper(struct kmsg_dumper *dumper);
+
+#endif /* _LINUX_DUMP_DEVICE_H */
diff --git a/kernel/panic.c b/kernel/panic.c
index c0b33b8..3a5a93f 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -10,6 +10,7 @@
  */
 #include <linux/debug_locks.h>
 #include <linux/interrupt.h>
+#include <linux/kmsg_dump.h>
 #include <linux/kallsyms.h>
 #include <linux/notifier.h>
 #include <linux/module.h>
@@ -76,6 +77,7 @@ NORET_TYPE void panic(const char * fmt, ...)
 	dump_stack();
 #endif
 
+	dump_kmsg(kmsg_dump_panic);
 	/*
 	 * If we have crashed and we have a crash kernel loaded let it handle
 	 * everything else.
@@ -341,6 +343,7 @@ void oops_exit(void)
 {
 	do_oops_enter_exit();
 	print_oops_end_marker();
+	dump_kmsg(kmsg_dump_oops);
 }
 
 #ifdef WANT_WARN_ON_SLOWPATH
diff --git a/kernel/printk.c b/kernel/printk.c
index f38b07f..9c4d9cb 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -33,6 +33,8 @@
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
+#include <linux/kmsg_dump.h>
+#include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
 
@@ -1405,3 +1407,105 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 }
 EXPORT_SYMBOL(printk_timed_ratelimit);
 #endif
+
+static LIST_HEAD(dump_list);
+static DEFINE_SPINLOCK(dump_list_lock);
+
+/**
+ *	register_dump_device - register a kernel log dumper.
+ *	@dump: pointer to the dump structure
+ *	@priv: private data for the structure
+ *
+ *	Adds a kernel log dumper to the system. The dump callback in the
+ *	structure will be called when the kernel oopses or panics and must be
+ *	set. Returns zero on success and -EINVAL or -EBUSY otherwise.
+ */
+int register_kmsg_dumper(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	/* The dump callback needs to be set */
+	if (!dumper->dump)
+		return -EINVAL;
+
+	/* Don't allow registering multiple times */
+	if (dumper->registered)
+		return -EBUSY;
+
+	dumper->registered = 1;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	list_add(&dumper->list, &dump_list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL(register_kmsg_dumper);
+
+/**
+ *	unregister_dump_device - unregister a dumpdevice.
+ *	@dump: pointer to the dump structure
+ *
+ *	Removes a dump device from the system.
+ */
+void unregister_kmsg_dumper(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	list_del(&dumper->list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+}
+EXPORT_SYMBOL(unregister_kmsg_dumper);
+
+static const char *kmsg_reasons[] = {
+	[kmsg_dump_oops]	= "oops",
+	[kmsg_dump_panic]	= "panic",
+};
+
+static const char *kmsg_to_str(enum kmsg_dump_reason reason)
+{
+	if (reason > ARRAY_SIZE(kmsg_reasons) || reason < 0)
+		return "unknown";
+
+	return kmsg_reasons[reason];
+}
+
+/**
+ *	dump_kmsg - dump kernel log to kernel message dumpers.
+ *	@reason: the reason (oops, panic etc) for dumping
+ *
+ *	Iterate through each of the dump devices and call the oops/panic
+ *	callbacks with the log buffer.
+ */
+void dump_kmsg(enum kmsg_dump_reason reason)
+{
+	unsigned long len = ACCESS_ONCE(log_end);
+	struct kmsg_dumper *dumper;
+	const char *s1, *s2;
+	unsigned long l1, l2;
+
+	s1 = "";
+	l1 = 0;
+	s2 = log_buf;
+	l2 = len;
+
+	/* Have we rotated around the circular buffer? */
+	if (len > log_buf_len) {
+		unsigned long pos = len & LOG_BUF_MASK;
+
+		s1 = log_buf + pos;
+		l1 = log_buf_len - pos;
+
+		s2 = log_buf;
+		l2 = pos;
+	}
+
+	if (!spin_trylock(&dump_list_lock)) {
+		printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n",
+				kmsg_to_str(reason));
+		return;
+	}
+	list_for_each_entry(dumper, &dump_list, list)
+		dumper->dump(dumper, reason, s1, l1, s2, l2);
+	spin_unlock(&dump_list_lock);
+}
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v7 5/5]: mtdoops: refactor as a kmsg_dumper
  2009-10-15  7:40 [PATCH v7 0/5]: mtdoops: fixes and improvements Simon Kagstrom
                   ` (3 preceding siblings ...)
  2009-10-15  7:48   ` Simon Kagstrom
@ 2009-10-15  7:48 ` Simon Kagstrom
  2009-10-15 14:10   ` [PATCH v8 " Simon Kagstrom
                     ` (2 more replies)
  2009-10-29 12:35 ` [PATCH v12 0/4]: mtdoops: fixes and improvements Simon Kagstrom
  5 siblings, 3 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-15  7:48 UTC (permalink / raw)
  To: Artem Bityutskiy, linux-mtd; +Cc: David Woodhouse

The last messages which happens before a crash might contain interesting
information about the crash. This patch reworks mtdoops using the
kmsg_dumper support instead of a console, which simplifies the code and
also includes the messages before the oops started.

On oops callbacks, the MTD device write is scheduled in a work queue (to
be able to use the regular mtd->write call), while panics call
mtd->panic_write directly. Thus, if panic_on_oops is set, the oops will
be written out during the panic.

A parameter to specify which mtd device to use (number or name), as well
as a flag, writable at runtime, to toggle wheter to dump oopses or only
panics (since oopses can often be handled by regular syslog).

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
---
ChangeLog:
	* (Vimal Singh) Correct Kconfig instructions on how to load
	  the module
	* Correct kfree of unallocated area
        * More descriptive error message on wrong module parameters
	* Rebase against new patch 4 (use container_of instead of private
          pointer)

 drivers/mtd/Kconfig   |    5 +-
 drivers/mtd/mtdoops.c |  211 ++++++++++++++++++++-----------------------------
 2 files changed, 88 insertions(+), 128 deletions(-)

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index ecf90f5..60d6c31 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -312,8 +312,9 @@ config MTD_OOPS
 	  buffer in a flash partition where it can be read back at some
 	  later point.
 
-	  To use, add console=ttyMTDx to the kernel command line,
-	  where x is the MTD device number to use.
+	  To use, add mtddev=name/number to the kernel command line,
+	  where name/number is the name or number of the MTD device
+	  to use (e.g., mtddev=7 for /dev/mtd7).
 
 source "drivers/mtd/chips/Kconfig"
 
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 2870a11..d7da953 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -29,18 +29,31 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/delay.h>
-#include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
+#include <linux/kmsg_dump.h>
 
 #define MTDOOPS_KERNMSG_MAGIC 0x5d005d00
+#define MTDOOPS_HEADER_SIZE   8
 
 static unsigned long record_size = 4096;
 module_param(record_size, ulong, 0400);
 MODULE_PARM_DESC(record_size,
 		"record size for MTD OOPS pages in bytes (default 4096)");
 
+static char mtddev[80];
+module_param_string(mtddev, mtddev, 80, 0400);
+MODULE_PARM_DESC(mtddev,
+		"name or index number of the MTD device to use");
+
+static int dump_oops = 1;
+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 struct mtdoops_context {
+	struct kmsg_dumper dump;
+
 	int mtd_index;
 	struct work_struct work_erase;
 	struct work_struct work_write;
@@ -49,14 +62,8 @@ static struct mtdoops_context {
 	int nextpage;
 	int nextcount;
 	unsigned long *oops_page_used;
-	char *name;
 
 	void *oops_buf;
-
-	/* writecount and disabling ready are spin lock protected */
-	spinlock_t writecount_lock;
-	int ready;
-	int writecount;
 } oops_cxt;
 
 static void mark_page_used(struct mtdoops_context *cxt, int page)
@@ -108,7 +115,7 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
 		remove_wait_queue(&wait_q, &wait);
 		printk(KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] on \"%s\" failed\n",
 		       (unsigned long long)erase.addr,
-		       (unsigned long long)erase.len, mtd->name);
+		       (unsigned long long)erase.len, mtddev);
 		return ret;
 	}
 
@@ -138,7 +145,6 @@ static void mtdoops_inc_counter(struct mtdoops_context *cxt)
 
 	printk(KERN_DEBUG "mtdoops: ready %d, %d (no erase)\n",
 	       cxt->nextpage, cxt->nextcount);
-	cxt->ready = 1;
 }
 
 /* Scheduled work - when we can't proceed without erasing a block */
@@ -187,7 +193,6 @@ badblock:
 	if (ret >= 0) {
 		printk(KERN_DEBUG "mtdoops: ready %d, %d\n",
 		       cxt->nextpage, cxt->nextcount);
-		cxt->ready = 1;
 		return;
 	}
 
@@ -205,11 +210,13 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 {
 	struct mtd_info *mtd = cxt->mtd;
 	size_t retlen;
+	u32 *hdr;
 	int ret;
 
-	if (cxt->writecount < record_size)
-		memset(cxt->oops_buf + cxt->writecount, 0xff,
-					record_size - cxt->writecount);
+	/* Add mtdoops header to the buffer */
+	hdr = cxt->oops_buf;
+	hdr[0] = cxt->nextcount;
+	hdr[1] = MTDOOPS_KERNMSG_MAGIC;
 
 	if (panic)
 		ret = mtd->panic_write(mtd, cxt->nextpage * record_size,
@@ -218,17 +225,15 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 		ret = mtd->write(mtd, cxt->nextpage * record_size,
 					record_size, &retlen, cxt->oops_buf);
 
-	cxt->writecount = 0;
-
 	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);
 	mark_page_used(cxt, cxt->nextpage);
+	memset(cxt->oops_buf, 0xff, record_size);
 
 	mtdoops_inc_counter(cxt);
 }
 
-
 static void mtdoops_workfunc_write(struct work_struct *work)
 {
 	struct mtdoops_context *cxt =
@@ -247,10 +252,13 @@ static void find_next_position(struct mtdoops_context *cxt)
 	for (page = 0; page < cxt->oops_pages; page++) {
 		/* Assume the page is used */
 		mark_page_used(cxt, page);
-		ret = mtd->read(mtd, page * record_size, 8, &retlen, (u_char *) &count[0]);
-		if (retlen != 8 || (ret < 0 && ret != -EUCLEAN)) {
-			printk(KERN_ERR "mtdoops: read failure at %ld (%td of 8 read), err %d\n",
-			       page * record_size, retlen, ret);
+		ret = mtd->read(mtd, page * record_size, MTDOOPS_HEADER_SIZE,
+				&retlen, (u_char *) &count[0]);
+		if (retlen != MTDOOPS_HEADER_SIZE ||
+				(ret < 0 && ret != -EUCLEAN)) {
+			printk(KERN_ERR "mtdoops: read failure at %ld (%td of %d read), err %d\n",
+			       page * record_size, retlen,
+			       MTDOOPS_HEADER_SIZE, ret);
 			continue;
 		}
 
@@ -287,7 +295,6 @@ static void find_next_position(struct mtdoops_context *cxt)
 		} else {
 			printk(KERN_DEBUG "mtdoops: ready %d, %d (clean)\n",
 			       cxt->nextpage, cxt->nextcount);
-			cxt->ready = 1;
 		}
 		return;
 	}
@@ -298,6 +305,42 @@ 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)
+{
+	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;
+
+	/* 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;
+
+	memcpy(dst, s1 + s1_start, l1_cpy);
+	memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
+
+	/* Panics must be written immediately */
+	if (reason == kmsg_dump_panic) {
+		if (!cxt->mtd->panic_write)
+			printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n");
+		else
+			mtdoops_write(cxt, 1);
+		return;
+	}
+
+	/* For other cases, schedule work to write it "nicely" */
+	schedule_work(&cxt->work_write);
+}
 
 static void mtdoops_notify_add(struct mtd_info *mtd)
 {
@@ -306,7 +349,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 
 	do_div(mtdoops_pages, record_size);
 
-	if (cxt->name && !strcmp(mtd->name, cxt->name))
+	if (!strcmp(mtd->name, mtddev))
 		cxt->mtd_index = mtd->index;
 
 	if (mtd->index != cxt->mtd_index || cxt->mtd_index < 0)
@@ -339,6 +382,8 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 
 	find_next_position(cxt);
 
+	cxt->dump.dump = mtdoops_do_dump;
+	register_kmsg_dumper(&cxt->dump);
 	printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index);
 }
 
@@ -349,116 +394,27 @@ static void mtdoops_notify_remove(struct mtd_info *mtd)
 	if (mtd->index != cxt->mtd_index || cxt->mtd_index < 0)
 		return;
 
+	unregister_kmsg_dumper(&cxt->dump);
 	cxt->mtd = NULL;
 	flush_scheduled_work();
 }
 
-static void mtdoops_console_sync(void)
-{
-	struct mtdoops_context *cxt = &oops_cxt;
-	struct mtd_info *mtd = cxt->mtd;
-	unsigned long flags;
-
-	if (!cxt->ready || !mtd || cxt->writecount == 0)
-		return;
-
-	/*
-	 *  Once ready is 0 and we've held the lock no further writes to the
-	 *  buffer will happen
-	 */
-	spin_lock_irqsave(&cxt->writecount_lock, flags);
-	if (!cxt->ready) {
-		spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-		return;
-	}
-	cxt->ready = 0;
-	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-
-	if (mtd->panic_write && (in_interrupt() || panic_on_oops))
-		/* Interrupt context, we're going to panic so try and log */
-		mtdoops_write(cxt, 1);
-	else
-		schedule_work(&cxt->work_write);
-}
-
-static void
-mtdoops_console_write(struct console *co, const char *s, unsigned int count)
-{
-	struct mtdoops_context *cxt = co->data;
-	struct mtd_info *mtd = cxt->mtd;
-	unsigned long flags;
-
-	if (!oops_in_progress) {
-		mtdoops_console_sync();
-		return;
-	}
-
-	if (!cxt->ready || !mtd)
-		return;
-
-	/* Locking on writecount ensures sequential writes to the buffer */
-	spin_lock_irqsave(&cxt->writecount_lock, flags);
-
-	/* Check ready status didn't change whilst waiting for the lock */
-	if (!cxt->ready) {
-		spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-		return;
-	}
-
-	if (cxt->writecount == 0) {
-		u32 *stamp = cxt->oops_buf;
-		*stamp++ = cxt->nextcount;
-		*stamp = MTDOOPS_KERNMSG_MAGIC;
-		cxt->writecount = 8;
-	}
-
-	if (count + cxt->writecount > record_size)
-		count = record_size - cxt->writecount;
-
-	memcpy(cxt->oops_buf + cxt->writecount, s, count);
-	cxt->writecount += count;
-
-	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-
-	if (cxt->writecount == record_size)
-		mtdoops_console_sync();
-}
-
-static int __init mtdoops_console_setup(struct console *co, char *options)
-{
-	struct mtdoops_context *cxt = co->data;
-
-	if (cxt->mtd_index != -1 || cxt->name)
-		return -EBUSY;
-	if (options) {
-		cxt->name = kstrdup(options, GFP_KERNEL);
-		return 0;
-	}
-	if (co->index == -1)
-		return -EINVAL;
-
-	cxt->mtd_index = co->index;
-	return 0;
-}
 
 static struct mtd_notifier mtdoops_notifier = {
 	.add	= mtdoops_notify_add,
 	.remove	= mtdoops_notify_remove,
 };
 
-static struct console mtdoops_console = {
-	.name		= "ttyMTD",
-	.write		= mtdoops_console_write,
-	.setup		= mtdoops_console_setup,
-	.unblank	= mtdoops_console_sync,
-	.index		= -1,
-	.data		= &oops_cxt,
-};
-
-static int __init mtdoops_console_init(void)
+static int __init mtdoops_init(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
+	int mtd_index;
+	char *endp;
 
+	if (strlen(mtddev) == 0) {
+		printk(KERN_ERR "mtdoops: mtd device (mtddev=name/number) must be supplied\n");
+		return -EINVAL;
+	}
 	if ((record_size & 4095) != 0) {
 		printk(KERN_ERR "mtdoops: record_size must be a multiple of 4096\n");
 		return -EINVAL;
@@ -467,36 +423,39 @@ static int __init mtdoops_console_init(void)
 		printk(KERN_ERR "mtdoops: record_size must be over 4096 bytes\n");
 		return -EINVAL;
 	}
+
+	/* Setup the MTD device to use */
 	cxt->mtd_index = -1;
+	mtd_index = simple_strtoul(mtddev, &endp, 0);
+	if (endp != mtddev)
+		cxt->mtd_index = mtd_index;
+
 	cxt->oops_buf = vmalloc(record_size);
 	if (!cxt->oops_buf) {
 		printk(KERN_ERR "mtdoops: failed to allocate buffer workspace\n");
 		return -ENOMEM;
 	}
+	memset(cxt->oops_buf, 0xff, record_size);
 
-	spin_lock_init(&cxt->writecount_lock);
 	INIT_WORK(&cxt->work_erase, mtdoops_workfunc_erase);
 	INIT_WORK(&cxt->work_write, mtdoops_workfunc_write);
 
-	register_console(&mtdoops_console);
 	register_mtd_user(&mtdoops_notifier);
 	return 0;
 }
 
-static void __exit mtdoops_console_exit(void)
+static void __exit mtdoops_exit(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
 
 	unregister_mtd_user(&mtdoops_notifier);
-	unregister_console(&mtdoops_console);
-	kfree(cxt->name);
 	vfree(cxt->oops_buf);
 	vfree(cxt->oops_page_used);
 }
 
 
-subsys_initcall(mtdoops_console_init);
-module_exit(mtdoops_console_exit);
+module_init(mtdoops_init);
+module_exit(mtdoops_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* Re: [PATCH v7 4/5]: core: Add kernel message dumper to call on oopses and panics
  2009-10-15  7:48   ` Simon Kagstrom
@ 2009-10-15  9:31     ` Ingo Molnar
  -1 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-15  9:31 UTC (permalink / raw)
  To: Simon Kagstrom
  Cc: Linus Torvalds, linux-mtd, Artem Bityutskiy, David Woodhouse,
	Andrew Morton, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox


* Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:

> --- /dev/null
> +++ b/include/linux/kmsg_dump.h

> +enum kmsg_dump_reason {
> +	kmsg_dump_oops,
> +	kmsg_dump_panic,
> +};

Please capitalize constants - lower case suggests it's some sort of 
variable which it is not.

> +void dump_kmsg(enum kmsg_dump_reason reason);
> +
> +int register_kmsg_dumper(struct kmsg_dumper *dumper);
> +
> +void unregister_kmsg_dumper(struct kmsg_dumper *dumper);

Please rename these APIs to be more in line with how we name new kernel 
APIs. Something like:

  kmsg_dump()
  kmsg_dumper_register()
  kmsg_dumper_unregister()

(we start with the subsystem as a prefix, then we go from more generic 
to less generic words.)

Might even make sense to name them all kmsg_dump:

  kmsg_dump()
  kmsg_dump_register()
  kmsg_dump_unregister()

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v7 4/5]: core: Add kernel message dumper to call on oopses and panics
@ 2009-10-15  9:31     ` Ingo Molnar
  0 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-15  9:31 UTC (permalink / raw)
  To: Simon Kagstrom
  Cc: Artem Bityutskiy, David Woodhouse, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Andrew Morton, Linus Torvalds, Alan Cox


* Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:

> --- /dev/null
> +++ b/include/linux/kmsg_dump.h

> +enum kmsg_dump_reason {
> +	kmsg_dump_oops,
> +	kmsg_dump_panic,
> +};

Please capitalize constants - lower case suggests it's some sort of 
variable which it is not.

> +void dump_kmsg(enum kmsg_dump_reason reason);
> +
> +int register_kmsg_dumper(struct kmsg_dumper *dumper);
> +
> +void unregister_kmsg_dumper(struct kmsg_dumper *dumper);

Please rename these APIs to be more in line with how we name new kernel 
APIs. Something like:

  kmsg_dump()
  kmsg_dumper_register()
  kmsg_dumper_unregister()

(we start with the subsystem as a prefix, then we go from more generic 
to less generic words.)

Might even make sense to name them all kmsg_dump:

  kmsg_dump()
  kmsg_dump_register()
  kmsg_dump_unregister()

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v8 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-15  9:31     ` Ingo Molnar
@ 2009-10-15 14:10       ` Simon Kagstrom
  -1 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-15 14:10 UTC (permalink / raw)
  To: Ingo Molnar, linux-mtd
  Cc: Linus Torvalds, Artem Bityutskiy, David Woodhouse, Andrew Morton,
	LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

The core functionality is implemented as per Linus suggestion from

  http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html

(with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
been added which contains a callback to dump the kernel log buffers on
crashes. The kmsg_dump function gets called from oops_exit() and panic()
and invokes this callbacks with the crash reason.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
---
ChangeLog:
        * (Ingo Molnar) rename functions to new standard
	* (Ingo Molnar) use capitals for constants

 include/linux/kmsg_dump.h |   36 +++++++++++++++
 kernel/panic.c            |    3 +
 kernel/printk.c           |  104 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/kmsg_dump.h

diff --git a/include/linux/kmsg_dump.h b/include/linux/kmsg_dump.h
new file mode 100644
index 0000000..4fb9d29
--- /dev/null
+++ b/include/linux/kmsg_dump.h
@@ -0,0 +1,36 @@
+/*
+ * linux/include/kmsg_dump.h
+ *
+ * Copyright (C) 2009 Net Insight AB
+ *
+ * Author: Simon Kagstrom <simon.kagstrom@netinsight.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+#ifndef _LINUX_KMSG_DUMP_H
+#define _LINUX_KMSG_DUMP_H
+
+#include <linux/list.h>
+
+enum kmsg_dump_reason {
+	KMSG_DUMP_OOPS,
+	KMSG_DUMP_PANIC,
+};
+
+struct kmsg_dumper {
+	void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
+			const char *s1, unsigned long l1,
+			const char *s2, unsigned long l2);
+	struct list_head list;
+	int registered;
+};
+
+void kmsg_dump(enum kmsg_dump_reason reason);
+
+int kmsg_dump_register(struct kmsg_dumper *dumper);
+
+void kmsg_dump_unregister(struct kmsg_dumper *dumper);
+
+#endif /* _LINUX_DUMP_DEVICE_H */
diff --git a/kernel/panic.c b/kernel/panic.c
index c0b33b8..763296d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -10,6 +10,7 @@
  */
 #include <linux/debug_locks.h>
 #include <linux/interrupt.h>
+#include <linux/kmsg_dump.h>
 #include <linux/kallsyms.h>
 #include <linux/notifier.h>
 #include <linux/module.h>
@@ -76,6 +77,7 @@ NORET_TYPE void panic(const char * fmt, ...)
 	dump_stack();
 #endif
 
+	kmsg_dump(KMSG_DUMP_PANIC);
 	/*
 	 * If we have crashed and we have a crash kernel loaded let it handle
 	 * everything else.
@@ -341,6 +343,7 @@ void oops_exit(void)
 {
 	do_oops_enter_exit();
 	print_oops_end_marker();
+	kmsg_dump(KMSG_DUMP_OOPS);
 }
 
 #ifdef WANT_WARN_ON_SLOWPATH
diff --git a/kernel/printk.c b/kernel/printk.c
index f38b07f..960406a 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -33,6 +33,8 @@
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
+#include <linux/kmsg_dump.h>
+#include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
 
@@ -1405,3 +1407,105 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 }
 EXPORT_SYMBOL(printk_timed_ratelimit);
 #endif
+
+static LIST_HEAD(dump_list);
+static DEFINE_SPINLOCK(dump_list_lock);
+
+/**
+ *	kmsg_dump_register - register a kernel log dumper.
+ *	@dump: pointer to the kmsg_dumper structure
+ *	@priv: private data for the structure
+ *
+ *	Adds a kernel log dumper to the system. The dump callback in the
+ *	structure will be called when the kernel oopses or panics and must be
+ *	set. Returns zero on success and -EINVAL or -EBUSY otherwise.
+ */
+int kmsg_dump_register(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	/* The dump callback needs to be set */
+	if (!dumper->dump)
+		return -EINVAL;
+
+	/* Don't allow registering multiple times */
+	if (dumper->registered)
+		return -EBUSY;
+
+	dumper->registered = 1;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	list_add(&dumper->list, &dump_list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL(kmsg_dump_register);
+
+/**
+ *	kmsg_dump_unregister - unregister a kmsg dumper.
+ *	@dump: pointer to the kmsg_dumper structure
+ *
+ *	Removes a dump device from the system.
+ */
+void kmsg_dump_unregister(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	list_del(&dumper->list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+}
+EXPORT_SYMBOL(kmsg_dump_unregister);
+
+static const char *kmsg_reasons[] = {
+	[KMSG_DUMP_OOPS]	= "oops",
+	[KMSG_DUMP_PANIC]	= "panic",
+};
+
+static const char *kmsg_to_str(enum kmsg_dump_reason reason)
+{
+	if (reason > ARRAY_SIZE(kmsg_reasons) || reason < 0)
+		return "unknown";
+
+	return kmsg_reasons[reason];
+}
+
+/**
+ *	dump_kmsg - dump kernel log to kernel message dumpers.
+ *	@reason: the reason (oops, panic etc) for dumping
+ *
+ *	Iterate through each of the dump devices and call the oops/panic
+ *	callbacks with the log buffer.
+ */
+void kmsg_dump(enum kmsg_dump_reason reason)
+{
+	unsigned long len = ACCESS_ONCE(log_end);
+	struct kmsg_dumper *dumper;
+	const char *s1, *s2;
+	unsigned long l1, l2;
+
+	s1 = "";
+	l1 = 0;
+	s2 = log_buf;
+	l2 = len;
+
+	/* Have we rotated around the circular buffer? */
+	if (len > log_buf_len) {
+		unsigned long pos = len & LOG_BUF_MASK;
+
+		s1 = log_buf + pos;
+		l1 = log_buf_len - pos;
+
+		s2 = log_buf;
+		l2 = pos;
+	}
+
+	if (!spin_trylock(&dump_list_lock)) {
+		printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n",
+				kmsg_to_str(reason));
+		return;
+	}
+	list_for_each_entry(dumper, &dump_list, list)
+		dumper->dump(dumper, reason, s1, l1, s2, l2);
+	spin_unlock(&dump_list_lock);
+}
-- 
1.6.0.4


^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v8 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-15 14:10       ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-15 14:10 UTC (permalink / raw)
  To: Ingo Molnar, linux-mtd
  Cc: Artem Bityutskiy, Linus Torvalds, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	Andrew Morton, David Woodhouse, Alan Cox

The core functionality is implemented as per Linus suggestion from

  http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html

(with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
been added which contains a callback to dump the kernel log buffers on
crashes. The kmsg_dump function gets called from oops_exit() and panic()
and invokes this callbacks with the crash reason.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
---
ChangeLog:
        * (Ingo Molnar) rename functions to new standard
	* (Ingo Molnar) use capitals for constants

 include/linux/kmsg_dump.h |   36 +++++++++++++++
 kernel/panic.c            |    3 +
 kernel/printk.c           |  104 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/kmsg_dump.h

diff --git a/include/linux/kmsg_dump.h b/include/linux/kmsg_dump.h
new file mode 100644
index 0000000..4fb9d29
--- /dev/null
+++ b/include/linux/kmsg_dump.h
@@ -0,0 +1,36 @@
+/*
+ * linux/include/kmsg_dump.h
+ *
+ * Copyright (C) 2009 Net Insight AB
+ *
+ * Author: Simon Kagstrom <simon.kagstrom@netinsight.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+#ifndef _LINUX_KMSG_DUMP_H
+#define _LINUX_KMSG_DUMP_H
+
+#include <linux/list.h>
+
+enum kmsg_dump_reason {
+	KMSG_DUMP_OOPS,
+	KMSG_DUMP_PANIC,
+};
+
+struct kmsg_dumper {
+	void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
+			const char *s1, unsigned long l1,
+			const char *s2, unsigned long l2);
+	struct list_head list;
+	int registered;
+};
+
+void kmsg_dump(enum kmsg_dump_reason reason);
+
+int kmsg_dump_register(struct kmsg_dumper *dumper);
+
+void kmsg_dump_unregister(struct kmsg_dumper *dumper);
+
+#endif /* _LINUX_DUMP_DEVICE_H */
diff --git a/kernel/panic.c b/kernel/panic.c
index c0b33b8..763296d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -10,6 +10,7 @@
  */
 #include <linux/debug_locks.h>
 #include <linux/interrupt.h>
+#include <linux/kmsg_dump.h>
 #include <linux/kallsyms.h>
 #include <linux/notifier.h>
 #include <linux/module.h>
@@ -76,6 +77,7 @@ NORET_TYPE void panic(const char * fmt, ...)
 	dump_stack();
 #endif
 
+	kmsg_dump(KMSG_DUMP_PANIC);
 	/*
 	 * If we have crashed and we have a crash kernel loaded let it handle
 	 * everything else.
@@ -341,6 +343,7 @@ void oops_exit(void)
 {
 	do_oops_enter_exit();
 	print_oops_end_marker();
+	kmsg_dump(KMSG_DUMP_OOPS);
 }
 
 #ifdef WANT_WARN_ON_SLOWPATH
diff --git a/kernel/printk.c b/kernel/printk.c
index f38b07f..960406a 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -33,6 +33,8 @@
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
+#include <linux/kmsg_dump.h>
+#include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
 
@@ -1405,3 +1407,105 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 }
 EXPORT_SYMBOL(printk_timed_ratelimit);
 #endif
+
+static LIST_HEAD(dump_list);
+static DEFINE_SPINLOCK(dump_list_lock);
+
+/**
+ *	kmsg_dump_register - register a kernel log dumper.
+ *	@dump: pointer to the kmsg_dumper structure
+ *	@priv: private data for the structure
+ *
+ *	Adds a kernel log dumper to the system. The dump callback in the
+ *	structure will be called when the kernel oopses or panics and must be
+ *	set. Returns zero on success and -EINVAL or -EBUSY otherwise.
+ */
+int kmsg_dump_register(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	/* The dump callback needs to be set */
+	if (!dumper->dump)
+		return -EINVAL;
+
+	/* Don't allow registering multiple times */
+	if (dumper->registered)
+		return -EBUSY;
+
+	dumper->registered = 1;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	list_add(&dumper->list, &dump_list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL(kmsg_dump_register);
+
+/**
+ *	kmsg_dump_unregister - unregister a kmsg dumper.
+ *	@dump: pointer to the kmsg_dumper structure
+ *
+ *	Removes a dump device from the system.
+ */
+void kmsg_dump_unregister(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	list_del(&dumper->list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+}
+EXPORT_SYMBOL(kmsg_dump_unregister);
+
+static const char *kmsg_reasons[] = {
+	[KMSG_DUMP_OOPS]	= "oops",
+	[KMSG_DUMP_PANIC]	= "panic",
+};
+
+static const char *kmsg_to_str(enum kmsg_dump_reason reason)
+{
+	if (reason > ARRAY_SIZE(kmsg_reasons) || reason < 0)
+		return "unknown";
+
+	return kmsg_reasons[reason];
+}
+
+/**
+ *	dump_kmsg - dump kernel log to kernel message dumpers.
+ *	@reason: the reason (oops, panic etc) for dumping
+ *
+ *	Iterate through each of the dump devices and call the oops/panic
+ *	callbacks with the log buffer.
+ */
+void kmsg_dump(enum kmsg_dump_reason reason)
+{
+	unsigned long len = ACCESS_ONCE(log_end);
+	struct kmsg_dumper *dumper;
+	const char *s1, *s2;
+	unsigned long l1, l2;
+
+	s1 = "";
+	l1 = 0;
+	s2 = log_buf;
+	l2 = len;
+
+	/* Have we rotated around the circular buffer? */
+	if (len > log_buf_len) {
+		unsigned long pos = len & LOG_BUF_MASK;
+
+		s1 = log_buf + pos;
+		l1 = log_buf_len - pos;
+
+		s2 = log_buf;
+		l2 = pos;
+	}
+
+	if (!spin_trylock(&dump_list_lock)) {
+		printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n",
+				kmsg_to_str(reason));
+		return;
+	}
+	list_for_each_entry(dumper, &dump_list, list)
+		dumper->dump(dumper, reason, s1, l1, s2, l2);
+	spin_unlock(&dump_list_lock);
+}
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v8 5/5]: mtdoops: refactor as a kmsg_dumper
  2009-10-15  7:48 ` [PATCH v7 5/5]: mtdoops: refactor as a kmsg_dumper Simon Kagstrom
@ 2009-10-15 14:10   ` Simon Kagstrom
  2009-10-16  7:46     ` [PATCH v9 " Simon Kagstrom
  2009-10-23  4:32   ` [PATCH v7 " Artem Bityutskiy
  2010-01-06 14:33   ` David Woodhouse
  2 siblings, 1 reply; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-15 14:10 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: David Woodhouse, linux-mtd, Artem Bityutskiy

The last messages which happens before a crash might contain interesting
information about the crash. This patch reworks mtdoops using the
kmsg_dumper support instead of a console, which simplifies the code and
also includes the messages before the oops started.

On oops callbacks, the MTD device write is scheduled in a work queue (to
be able to use the regular mtd->write call), while panics call
mtd->panic_write directly. Thus, if panic_on_oops is set, the oops will
be written out during the panic.

A parameter to specify which mtd device to use (number or name), as well
as a flag, writable at runtime, to toggle wheter to dump oopses or only
panics (since oopses can often be handled by regular syslog).

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
---
ChangeLog:
	* Refactor against new version of patch 4

 drivers/mtd/Kconfig   |    5 +-
 drivers/mtd/mtdoops.c |  211 ++++++++++++++++++++-----------------------------
 2 files changed, 88 insertions(+), 128 deletions(-)

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index ecf90f5..60d6c31 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -312,8 +312,9 @@ config MTD_OOPS
 	  buffer in a flash partition where it can be read back at some
 	  later point.
 
-	  To use, add console=ttyMTDx to the kernel command line,
-	  where x is the MTD device number to use.
+	  To use, add mtddev=name/number to the kernel command line,
+	  where name/number is the name or number of the MTD device
+	  to use (e.g., mtddev=7 for /dev/mtd7).
 
 source "drivers/mtd/chips/Kconfig"
 
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 2870a11..3af1016 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -29,18 +29,31 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/delay.h>
-#include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
+#include <linux/kmsg_dump.h>
 
 #define MTDOOPS_KERNMSG_MAGIC 0x5d005d00
+#define MTDOOPS_HEADER_SIZE   8
 
 static unsigned long record_size = 4096;
 module_param(record_size, ulong, 0400);
 MODULE_PARM_DESC(record_size,
 		"record size for MTD OOPS pages in bytes (default 4096)");
 
+static char mtddev[80];
+module_param_string(mtddev, mtddev, 80, 0400);
+MODULE_PARM_DESC(mtddev,
+		"name or index number of the MTD device to use");
+
+static int dump_oops = 1;
+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 struct mtdoops_context {
+	struct kmsg_dumper dump;
+
 	int mtd_index;
 	struct work_struct work_erase;
 	struct work_struct work_write;
@@ -49,14 +62,8 @@ static struct mtdoops_context {
 	int nextpage;
 	int nextcount;
 	unsigned long *oops_page_used;
-	char *name;
 
 	void *oops_buf;
-
-	/* writecount and disabling ready are spin lock protected */
-	spinlock_t writecount_lock;
-	int ready;
-	int writecount;
 } oops_cxt;
 
 static void mark_page_used(struct mtdoops_context *cxt, int page)
@@ -108,7 +115,7 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
 		remove_wait_queue(&wait_q, &wait);
 		printk(KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] on \"%s\" failed\n",
 		       (unsigned long long)erase.addr,
-		       (unsigned long long)erase.len, mtd->name);
+		       (unsigned long long)erase.len, mtddev);
 		return ret;
 	}
 
@@ -138,7 +145,6 @@ static void mtdoops_inc_counter(struct mtdoops_context *cxt)
 
 	printk(KERN_DEBUG "mtdoops: ready %d, %d (no erase)\n",
 	       cxt->nextpage, cxt->nextcount);
-	cxt->ready = 1;
 }
 
 /* Scheduled work - when we can't proceed without erasing a block */
@@ -187,7 +193,6 @@ badblock:
 	if (ret >= 0) {
 		printk(KERN_DEBUG "mtdoops: ready %d, %d\n",
 		       cxt->nextpage, cxt->nextcount);
-		cxt->ready = 1;
 		return;
 	}
 
@@ -205,11 +210,13 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 {
 	struct mtd_info *mtd = cxt->mtd;
 	size_t retlen;
+	u32 *hdr;
 	int ret;
 
-	if (cxt->writecount < record_size)
-		memset(cxt->oops_buf + cxt->writecount, 0xff,
-					record_size - cxt->writecount);
+	/* Add mtdoops header to the buffer */
+	hdr = cxt->oops_buf;
+	hdr[0] = cxt->nextcount;
+	hdr[1] = MTDOOPS_KERNMSG_MAGIC;
 
 	if (panic)
 		ret = mtd->panic_write(mtd, cxt->nextpage * record_size,
@@ -218,17 +225,15 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 		ret = mtd->write(mtd, cxt->nextpage * record_size,
 					record_size, &retlen, cxt->oops_buf);
 
-	cxt->writecount = 0;
-
 	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);
 	mark_page_used(cxt, cxt->nextpage);
+	memset(cxt->oops_buf, 0xff, record_size);
 
 	mtdoops_inc_counter(cxt);
 }
 
-
 static void mtdoops_workfunc_write(struct work_struct *work)
 {
 	struct mtdoops_context *cxt =
@@ -247,10 +252,13 @@ static void find_next_position(struct mtdoops_context *cxt)
 	for (page = 0; page < cxt->oops_pages; page++) {
 		/* Assume the page is used */
 		mark_page_used(cxt, page);
-		ret = mtd->read(mtd, page * record_size, 8, &retlen, (u_char *) &count[0]);
-		if (retlen != 8 || (ret < 0 && ret != -EUCLEAN)) {
-			printk(KERN_ERR "mtdoops: read failure at %ld (%td of 8 read), err %d\n",
-			       page * record_size, retlen, ret);
+		ret = mtd->read(mtd, page * record_size, MTDOOPS_HEADER_SIZE,
+				&retlen, (u_char *) &count[0]);
+		if (retlen != MTDOOPS_HEADER_SIZE ||
+				(ret < 0 && ret != -EUCLEAN)) {
+			printk(KERN_ERR "mtdoops: read failure at %ld (%td of %d read), err %d\n",
+			       page * record_size, retlen,
+			       MTDOOPS_HEADER_SIZE, ret);
 			continue;
 		}
 
@@ -287,7 +295,6 @@ static void find_next_position(struct mtdoops_context *cxt)
 		} else {
 			printk(KERN_DEBUG "mtdoops: ready %d, %d (clean)\n",
 			       cxt->nextpage, cxt->nextcount);
-			cxt->ready = 1;
 		}
 		return;
 	}
@@ -298,6 +305,42 @@ 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)
+{
+	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;
+
+	/* 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;
+
+	memcpy(dst, s1 + s1_start, l1_cpy);
+	memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
+
+	/* Panics must be written immediately */
+	if (reason == KMSG_DUMP_PANIC) {
+		if (!cxt->mtd->panic_write)
+			printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n");
+		else
+			mtdoops_write(cxt, 1);
+		return;
+	}
+
+	/* For other cases, schedule work to write it "nicely" */
+	schedule_work(&cxt->work_write);
+}
 
 static void mtdoops_notify_add(struct mtd_info *mtd)
 {
@@ -306,7 +349,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 
 	do_div(mtdoops_pages, record_size);
 
-	if (cxt->name && !strcmp(mtd->name, cxt->name))
+	if (!strcmp(mtd->name, mtddev))
 		cxt->mtd_index = mtd->index;
 
 	if (mtd->index != cxt->mtd_index || cxt->mtd_index < 0)
@@ -339,6 +382,8 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 
 	find_next_position(cxt);
 
+	cxt->dump.dump = mtdoops_do_dump;
+	kmsg_dump_register(&cxt->dump);
 	printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index);
 }
 
@@ -349,116 +394,27 @@ static void mtdoops_notify_remove(struct mtd_info *mtd)
 	if (mtd->index != cxt->mtd_index || cxt->mtd_index < 0)
 		return;
 
+	kmsg_dump_unregister(&cxt->dump);
 	cxt->mtd = NULL;
 	flush_scheduled_work();
 }
 
-static void mtdoops_console_sync(void)
-{
-	struct mtdoops_context *cxt = &oops_cxt;
-	struct mtd_info *mtd = cxt->mtd;
-	unsigned long flags;
-
-	if (!cxt->ready || !mtd || cxt->writecount == 0)
-		return;
-
-	/*
-	 *  Once ready is 0 and we've held the lock no further writes to the
-	 *  buffer will happen
-	 */
-	spin_lock_irqsave(&cxt->writecount_lock, flags);
-	if (!cxt->ready) {
-		spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-		return;
-	}
-	cxt->ready = 0;
-	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-
-	if (mtd->panic_write && (in_interrupt() || panic_on_oops))
-		/* Interrupt context, we're going to panic so try and log */
-		mtdoops_write(cxt, 1);
-	else
-		schedule_work(&cxt->work_write);
-}
-
-static void
-mtdoops_console_write(struct console *co, const char *s, unsigned int count)
-{
-	struct mtdoops_context *cxt = co->data;
-	struct mtd_info *mtd = cxt->mtd;
-	unsigned long flags;
-
-	if (!oops_in_progress) {
-		mtdoops_console_sync();
-		return;
-	}
-
-	if (!cxt->ready || !mtd)
-		return;
-
-	/* Locking on writecount ensures sequential writes to the buffer */
-	spin_lock_irqsave(&cxt->writecount_lock, flags);
-
-	/* Check ready status didn't change whilst waiting for the lock */
-	if (!cxt->ready) {
-		spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-		return;
-	}
-
-	if (cxt->writecount == 0) {
-		u32 *stamp = cxt->oops_buf;
-		*stamp++ = cxt->nextcount;
-		*stamp = MTDOOPS_KERNMSG_MAGIC;
-		cxt->writecount = 8;
-	}
-
-	if (count + cxt->writecount > record_size)
-		count = record_size - cxt->writecount;
-
-	memcpy(cxt->oops_buf + cxt->writecount, s, count);
-	cxt->writecount += count;
-
-	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-
-	if (cxt->writecount == record_size)
-		mtdoops_console_sync();
-}
-
-static int __init mtdoops_console_setup(struct console *co, char *options)
-{
-	struct mtdoops_context *cxt = co->data;
-
-	if (cxt->mtd_index != -1 || cxt->name)
-		return -EBUSY;
-	if (options) {
-		cxt->name = kstrdup(options, GFP_KERNEL);
-		return 0;
-	}
-	if (co->index == -1)
-		return -EINVAL;
-
-	cxt->mtd_index = co->index;
-	return 0;
-}
 
 static struct mtd_notifier mtdoops_notifier = {
 	.add	= mtdoops_notify_add,
 	.remove	= mtdoops_notify_remove,
 };
 
-static struct console mtdoops_console = {
-	.name		= "ttyMTD",
-	.write		= mtdoops_console_write,
-	.setup		= mtdoops_console_setup,
-	.unblank	= mtdoops_console_sync,
-	.index		= -1,
-	.data		= &oops_cxt,
-};
-
-static int __init mtdoops_console_init(void)
+static int __init mtdoops_init(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
+	int mtd_index;
+	char *endp;
 
+	if (strlen(mtddev) == 0) {
+		printk(KERN_ERR "mtdoops: mtd device (mtddev=name/number) must be supplied\n");
+		return -EINVAL;
+	}
 	if ((record_size & 4095) != 0) {
 		printk(KERN_ERR "mtdoops: record_size must be a multiple of 4096\n");
 		return -EINVAL;
@@ -467,36 +423,39 @@ static int __init mtdoops_console_init(void)
 		printk(KERN_ERR "mtdoops: record_size must be over 4096 bytes\n");
 		return -EINVAL;
 	}
+
+	/* Setup the MTD device to use */
 	cxt->mtd_index = -1;
+	mtd_index = simple_strtoul(mtddev, &endp, 0);
+	if (endp != mtddev)
+		cxt->mtd_index = mtd_index;
+
 	cxt->oops_buf = vmalloc(record_size);
 	if (!cxt->oops_buf) {
 		printk(KERN_ERR "mtdoops: failed to allocate buffer workspace\n");
 		return -ENOMEM;
 	}
+	memset(cxt->oops_buf, 0xff, record_size);
 
-	spin_lock_init(&cxt->writecount_lock);
 	INIT_WORK(&cxt->work_erase, mtdoops_workfunc_erase);
 	INIT_WORK(&cxt->work_write, mtdoops_workfunc_write);
 
-	register_console(&mtdoops_console);
 	register_mtd_user(&mtdoops_notifier);
 	return 0;
 }
 
-static void __exit mtdoops_console_exit(void)
+static void __exit mtdoops_exit(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
 
 	unregister_mtd_user(&mtdoops_notifier);
-	unregister_console(&mtdoops_console);
-	kfree(cxt->name);
 	vfree(cxt->oops_buf);
 	vfree(cxt->oops_page_used);
 }
 
 
-subsys_initcall(mtdoops_console_init);
-module_exit(mtdoops_console_exit);
+module_init(mtdoops_init);
+module_exit(mtdoops_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* Re: [PATCH v8 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-15 14:10       ` Simon Kagstrom
@ 2009-10-15 15:46         ` Ingo Molnar
  -1 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-15 15:46 UTC (permalink / raw)
  To: Simon Kagstrom
  Cc: linux-mtd, Linus Torvalds, Artem Bityutskiy, David Woodhouse,
	Andrew Morton, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox


* Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:

> The core functionality is implemented as per Linus suggestion from
> 
>   http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html
> 
> (with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
> been added which contains a callback to dump the kernel log buffers on
> crashes. The kmsg_dump function gets called from oops_exit() and panic()
> and invokes this callbacks with the crash reason.
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>

The general structure looks very nice now! Assuming my review comments 
below are addressed all patches are:

  Reviewed-by: Ingo Molnar <mingo@elte.hu>

> diff --git a/kernel/printk.c b/kernel/printk.c
> index f38b07f..960406a 100644
> --- a/kernel/printk.c
> +++ b/kernel/printk.c
> @@ -33,6 +33,8 @@
>  #include <linux/bootmem.h>
>  #include <linux/syscalls.h>
>  #include <linux/kexec.h>
> +#include <linux/kmsg_dump.h>
> +#include <linux/spinlock.h>

( Small nit: in theory the spinlock.h include should not be needed as 
  printk.c already uses spinlocks and gets the types via mutex.h. )

>  
>  #include <asm/uaccess.h>
>  
> @@ -1405,3 +1407,105 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies,
>  }
>  EXPORT_SYMBOL(printk_timed_ratelimit);
>  #endif
> +
> +static LIST_HEAD(dump_list);
> +static DEFINE_SPINLOCK(dump_list_lock);

Please switch it around to be:

  static DEFINE_SPINLOCK(dump_list_lock);

  static LIST_HEAD(dump_list);

as the lock will be cacheline aligned on SMP, so the list head can come 
after it 'for free'.

If it's the other way around we'll use 8/16 more .data bytes on average.

> +
> +/**
> + *	kmsg_dump_register - register a kernel log dumper.
> + *	@dump: pointer to the kmsg_dumper structure
> + *	@priv: private data for the structure
> + *
> + *	Adds a kernel log dumper to the system. The dump callback in the
> + *	structure will be called when the kernel oopses or panics and must be
> + *	set. Returns zero on success and -EINVAL or -EBUSY otherwise.
> + */
> +int kmsg_dump_register(struct kmsg_dumper *dumper)
> +{
> +	unsigned long flags;
> +
> +	/* The dump callback needs to be set */
> +	if (!dumper->dump)
> +		return -EINVAL;
> +
> +	/* Don't allow registering multiple times */
> +	if (dumper->registered)
> +		return -EBUSY;
> +
> +	dumper->registered = 1;
> +
> +	spin_lock_irqsave(&dump_list_lock, flags);
> +	list_add(&dumper->list, &dump_list);
> +	spin_unlock_irqrestore(&dump_list_lock, flags);
> +	return 0;
> +}
> +EXPORT_SYMBOL(kmsg_dump_register);

There's a race here: dumper->registered should be set to 1 inside the 
spinlock - to make the register/unregister API SMP safe.

It probably doesnt matter much in practice right now (as the dumper will 
be registered during bootup and unregistered during shutdown), but still 
- it could matter to modular loading of multiple dumpers at once, in the 
future.

Also, the check for ->registered should be done inside too.

Plus a style nit: please put a newline before the 'return 0' - it looks 
more symmetric and separates the return from other code flow.

> +
> +/**
> + *	kmsg_dump_unregister - unregister a kmsg dumper.
> + *	@dump: pointer to the kmsg_dumper structure
> + *
> + *	Removes a dump device from the system.
> + */
> +void kmsg_dump_unregister(struct kmsg_dumper *dumper)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&dump_list_lock, flags);
> +	list_del(&dumper->list);
> +	spin_unlock_irqrestore(&dump_list_lock, flags);
> +}
> +EXPORT_SYMBOL(kmsg_dump_unregister);

I'd suggest for this API to use an error return as well, and to do it 
safely - i.e. any combination of these APIs should result in a safe 
result.

Right now a call sequence kmsg_dump_register() + kmsg_dump_unregister() 
+ kmsg_dump_register() will corrupt memory.

> +
> +static const char *kmsg_reasons[] = {
> +	[KMSG_DUMP_OOPS]	= "oops",
> +	[KMSG_DUMP_PANIC]	= "panic",
> +};

Should be 'const char const' for max constness.

> +static const char *kmsg_to_str(enum kmsg_dump_reason reason)
> +{
> +	if (reason > ARRAY_SIZE(kmsg_reasons) || reason < 0)
> +		return "unknown";

That should be ">=" i guess, for the check to be correct.

> +
> +	return kmsg_reasons[reason];
> +}
> +
> +/**
> + *	dump_kmsg - dump kernel log to kernel message dumpers.
> + *	@reason: the reason (oops, panic etc) for dumping
> + *
> + *	Iterate through each of the dump devices and call the oops/panic
> + *	callbacks with the log buffer.
> + */
> +void kmsg_dump(enum kmsg_dump_reason reason)
> +{
> +	unsigned long len = ACCESS_ONCE(log_end);
> +	struct kmsg_dumper *dumper;
> +	const char *s1, *s2;
> +	unsigned long l1, l2;
> +
> +	s1 = "";
> +	l1 = 0;
> +	s2 = log_buf;
> +	l2 = len;
> +
> +	/* Have we rotated around the circular buffer? */
> +	if (len > log_buf_len) {
> +		unsigned long pos = len & LOG_BUF_MASK;
> +
> +		s1 = log_buf + pos;
> +		l1 = log_buf_len - pos;
> +
> +		s2 = log_buf;
> +		l2 = pos;
> +	}
> +
> +	if (!spin_trylock(&dump_list_lock)) {
> +		printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n",
> +				kmsg_to_str(reason));
> +		return;
> +	}
> +	list_for_each_entry(dumper, &dump_list, list)
> +		dumper->dump(dumper, reason, s1, l1, s2, l2);
> +	spin_unlock(&dump_list_lock);
> +}

( Might make sense to use _irqsave()/_irqrestore() variants here - so 
  that if an IRQ comes in and panics too we dont recurse. The trylock 
  protects us above, but we are already non-preempt here - going irqsafe 
  is even better i guess. )

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v8 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-15 15:46         ` Ingo Molnar
  0 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-15 15:46 UTC (permalink / raw)
  To: Simon Kagstrom
  Cc: Artem Bityutskiy, David Woodhouse, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Andrew Morton, Linus Torvalds, Alan Cox


* Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:

> The core functionality is implemented as per Linus suggestion from
> 
>   http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html
> 
> (with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
> been added which contains a callback to dump the kernel log buffers on
> crashes. The kmsg_dump function gets called from oops_exit() and panic()
> and invokes this callbacks with the crash reason.
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>

The general structure looks very nice now! Assuming my review comments 
below are addressed all patches are:

  Reviewed-by: Ingo Molnar <mingo@elte.hu>

> diff --git a/kernel/printk.c b/kernel/printk.c
> index f38b07f..960406a 100644
> --- a/kernel/printk.c
> +++ b/kernel/printk.c
> @@ -33,6 +33,8 @@
>  #include <linux/bootmem.h>
>  #include <linux/syscalls.h>
>  #include <linux/kexec.h>
> +#include <linux/kmsg_dump.h>
> +#include <linux/spinlock.h>

( Small nit: in theory the spinlock.h include should not be needed as 
  printk.c already uses spinlocks and gets the types via mutex.h. )

>  
>  #include <asm/uaccess.h>
>  
> @@ -1405,3 +1407,105 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies,
>  }
>  EXPORT_SYMBOL(printk_timed_ratelimit);
>  #endif
> +
> +static LIST_HEAD(dump_list);
> +static DEFINE_SPINLOCK(dump_list_lock);

Please switch it around to be:

  static DEFINE_SPINLOCK(dump_list_lock);

  static LIST_HEAD(dump_list);

as the lock will be cacheline aligned on SMP, so the list head can come 
after it 'for free'.

If it's the other way around we'll use 8/16 more .data bytes on average.

> +
> +/**
> + *	kmsg_dump_register - register a kernel log dumper.
> + *	@dump: pointer to the kmsg_dumper structure
> + *	@priv: private data for the structure
> + *
> + *	Adds a kernel log dumper to the system. The dump callback in the
> + *	structure will be called when the kernel oopses or panics and must be
> + *	set. Returns zero on success and -EINVAL or -EBUSY otherwise.
> + */
> +int kmsg_dump_register(struct kmsg_dumper *dumper)
> +{
> +	unsigned long flags;
> +
> +	/* The dump callback needs to be set */
> +	if (!dumper->dump)
> +		return -EINVAL;
> +
> +	/* Don't allow registering multiple times */
> +	if (dumper->registered)
> +		return -EBUSY;
> +
> +	dumper->registered = 1;
> +
> +	spin_lock_irqsave(&dump_list_lock, flags);
> +	list_add(&dumper->list, &dump_list);
> +	spin_unlock_irqrestore(&dump_list_lock, flags);
> +	return 0;
> +}
> +EXPORT_SYMBOL(kmsg_dump_register);

There's a race here: dumper->registered should be set to 1 inside the 
spinlock - to make the register/unregister API SMP safe.

It probably doesnt matter much in practice right now (as the dumper will 
be registered during bootup and unregistered during shutdown), but still 
- it could matter to modular loading of multiple dumpers at once, in the 
future.

Also, the check for ->registered should be done inside too.

Plus a style nit: please put a newline before the 'return 0' - it looks 
more symmetric and separates the return from other code flow.

> +
> +/**
> + *	kmsg_dump_unregister - unregister a kmsg dumper.
> + *	@dump: pointer to the kmsg_dumper structure
> + *
> + *	Removes a dump device from the system.
> + */
> +void kmsg_dump_unregister(struct kmsg_dumper *dumper)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&dump_list_lock, flags);
> +	list_del(&dumper->list);
> +	spin_unlock_irqrestore(&dump_list_lock, flags);
> +}
> +EXPORT_SYMBOL(kmsg_dump_unregister);

I'd suggest for this API to use an error return as well, and to do it 
safely - i.e. any combination of these APIs should result in a safe 
result.

Right now a call sequence kmsg_dump_register() + kmsg_dump_unregister() 
+ kmsg_dump_register() will corrupt memory.

> +
> +static const char *kmsg_reasons[] = {
> +	[KMSG_DUMP_OOPS]	= "oops",
> +	[KMSG_DUMP_PANIC]	= "panic",
> +};

Should be 'const char const' for max constness.

> +static const char *kmsg_to_str(enum kmsg_dump_reason reason)
> +{
> +	if (reason > ARRAY_SIZE(kmsg_reasons) || reason < 0)
> +		return "unknown";

That should be ">=" i guess, for the check to be correct.

> +
> +	return kmsg_reasons[reason];
> +}
> +
> +/**
> + *	dump_kmsg - dump kernel log to kernel message dumpers.
> + *	@reason: the reason (oops, panic etc) for dumping
> + *
> + *	Iterate through each of the dump devices and call the oops/panic
> + *	callbacks with the log buffer.
> + */
> +void kmsg_dump(enum kmsg_dump_reason reason)
> +{
> +	unsigned long len = ACCESS_ONCE(log_end);
> +	struct kmsg_dumper *dumper;
> +	const char *s1, *s2;
> +	unsigned long l1, l2;
> +
> +	s1 = "";
> +	l1 = 0;
> +	s2 = log_buf;
> +	l2 = len;
> +
> +	/* Have we rotated around the circular buffer? */
> +	if (len > log_buf_len) {
> +		unsigned long pos = len & LOG_BUF_MASK;
> +
> +		s1 = log_buf + pos;
> +		l1 = log_buf_len - pos;
> +
> +		s2 = log_buf;
> +		l2 = pos;
> +	}
> +
> +	if (!spin_trylock(&dump_list_lock)) {
> +		printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n",
> +				kmsg_to_str(reason));
> +		return;
> +	}
> +	list_for_each_entry(dumper, &dump_list, list)
> +		dumper->dump(dumper, reason, s1, l1, s2, l2);
> +	spin_unlock(&dump_list_lock);
> +}

( Might make sense to use _irqsave()/_irqrestore() variants here - so 
  that if an IRQ comes in and panics too we dont recurse. The trylock 
  protects us above, but we are already non-preempt here - going irqsafe 
  is even better i guess. )

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v9 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-15 15:46         ` Ingo Molnar
@ 2009-10-16  7:46           ` Simon Kagstrom
  -1 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-16  7:46 UTC (permalink / raw)
  To: Ingo Molnar, linux-mtd
  Cc: Linus Torvalds, Artem Bityutskiy, David Woodhouse, Andrew Morton,
	LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

The core functionality is implemented as per Linus suggestion from

  http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html

(with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
been added which contains a callback to dump the kernel log buffers on
crashes. The kmsg_dump function gets called from oops_exit() and panic()
and invokes this callbacks with the crash reason.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
Reviewed-by: Ingo Molnar <mingo@elte.hu>
---
ChangeLog:
	* (Arjan van de Ven): Use EXPORT_SYMBOL_GPL
	* (Ingo Molnar): Switch list/spinlock definition order
	* (Ingo Molnar): Set/check ->registered within spinlocked region
	* (Ingo Molnar): Return error from unregister and check that the
	  dumper really is registered
	* (Ingo Molnar): Maximise constness and correct array check
	* (Ingo Molnar): Use _irqsave/_irqrestore also in kmsg_dump
	* (Ingo Molnar): Style fixes
	* (Anders Grafström): Correct kerneldoc names

 include/linux/kmsg_dump.h |   36 ++++++++++++++
 kernel/panic.c            |    3 +
 kernel/printk.c           |  116 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 155 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/kmsg_dump.h

diff --git a/include/linux/kmsg_dump.h b/include/linux/kmsg_dump.h
new file mode 100644
index 0000000..64296f3
--- /dev/null
+++ b/include/linux/kmsg_dump.h
@@ -0,0 +1,36 @@
+/*
+ * linux/include/kmsg_dump.h
+ *
+ * Copyright (C) 2009 Net Insight AB
+ *
+ * Author: Simon Kagstrom <simon.kagstrom@netinsight.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+#ifndef _LINUX_KMSG_DUMP_H
+#define _LINUX_KMSG_DUMP_H
+
+#include <linux/list.h>
+
+enum kmsg_dump_reason {
+	KMSG_DUMP_OOPS,
+	KMSG_DUMP_PANIC,
+};
+
+struct kmsg_dumper {
+	void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
+			const char *s1, unsigned long l1,
+			const char *s2, unsigned long l2);
+	struct list_head list;
+	int registered;
+};
+
+void kmsg_dump(enum kmsg_dump_reason reason);
+
+int kmsg_dump_register(struct kmsg_dumper *dumper);
+
+int kmsg_dump_unregister(struct kmsg_dumper *dumper);
+
+#endif /* _LINUX_DUMP_DEVICE_H */
diff --git a/kernel/panic.c b/kernel/panic.c
index c0b33b8..763296d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -10,6 +10,7 @@
  */
 #include <linux/debug_locks.h>
 #include <linux/interrupt.h>
+#include <linux/kmsg_dump.h>
 #include <linux/kallsyms.h>
 #include <linux/notifier.h>
 #include <linux/module.h>
@@ -76,6 +77,7 @@ NORET_TYPE void panic(const char * fmt, ...)
 	dump_stack();
 #endif
 
+	kmsg_dump(KMSG_DUMP_PANIC);
 	/*
 	 * If we have crashed and we have a crash kernel loaded let it handle
 	 * everything else.
@@ -341,6 +343,7 @@ void oops_exit(void)
 {
 	do_oops_enter_exit();
 	print_oops_end_marker();
+	kmsg_dump(KMSG_DUMP_OOPS);
 }
 
 #ifdef WANT_WARN_ON_SLOWPATH
diff --git a/kernel/printk.c b/kernel/printk.c
index f38b07f..d363306 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -33,6 +33,7 @@
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
+#include <linux/kmsg_dump.h>
 
 #include <asm/uaccess.h>
 
@@ -1405,3 +1406,118 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 }
 EXPORT_SYMBOL(printk_timed_ratelimit);
 #endif
+
+static DEFINE_SPINLOCK(dump_list_lock);
+static LIST_HEAD(dump_list);
+
+/**
+ *	kmsg_dump_register - register a kernel log dumper.
+ *	@dump: pointer to the kmsg_dumper structure
+ *
+ *	Adds a kernel log dumper to the system. The dump callback in the
+ *	structure will be called when the kernel oopses or panics and must be
+ *	set. Returns zero on success and -EINVAL or -EBUSY otherwise.
+ */
+int kmsg_dump_register(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	/* The dump callback needs to be set */
+	if (!dumper->dump)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+
+	/* Don't allow registering multiple times */
+	if (dumper->registered) {
+		spin_unlock_irqrestore(&dump_list_lock, flags);
+
+		return -EBUSY;
+	}
+
+	dumper->registered = 1;
+	list_add(&dumper->list, &dump_list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kmsg_dump_register);
+
+/**
+ *	kmsg_dump_unregister - unregister a kmsg dumper.
+ *	@dump: pointer to the kmsg_dumper structure
+ *
+ *	Removes a dump device from the system.
+ */
+int kmsg_dump_unregister(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	if (!dumper->registered) {
+		spin_unlock_irqrestore(&dump_list_lock, flags);
+
+		return -EINVAL;
+	}
+
+	dumper->registered = 0;
+	list_del(&dumper->list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
+
+static const char const *kmsg_reasons[] = {
+	[KMSG_DUMP_OOPS]	= "oops",
+	[KMSG_DUMP_PANIC]	= "panic",
+};
+
+static const char *kmsg_to_str(enum kmsg_dump_reason reason)
+{
+	if (reason >= ARRAY_SIZE(kmsg_reasons) || reason < 0)
+		return "unknown";
+
+	return kmsg_reasons[reason];
+}
+
+/**
+ *	kmsg_dump - dump kernel log to kernel message dumpers.
+ *	@reason: the reason (oops, panic etc) for dumping
+ *
+ *	Iterate through each of the dump devices and call the oops/panic
+ *	callbacks with the log buffer.
+ */
+void kmsg_dump(enum kmsg_dump_reason reason)
+{
+	unsigned long len = ACCESS_ONCE(log_end);
+	struct kmsg_dumper *dumper;
+	const char *s1, *s2;
+	unsigned long l1, l2;
+	unsigned long flags;
+
+	s1 = "";
+	l1 = 0;
+	s2 = log_buf;
+	l2 = len;
+
+	/* Have we rotated around the circular buffer? */
+	if (len > log_buf_len) {
+		unsigned long pos = len & LOG_BUF_MASK;
+
+		s1 = log_buf + pos;
+		l1 = log_buf_len - pos;
+
+		s2 = log_buf;
+		l2 = pos;
+	}
+
+	if (!spin_trylock_irqsave(&dump_list_lock, flags)) {
+		printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n",
+				kmsg_to_str(reason));
+		return;
+	}
+	list_for_each_entry(dumper, &dump_list, list)
+		dumper->dump(dumper, reason, s1, l1, s2, l2);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+}
-- 
1.6.0.4


^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v9 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-16  7:46           ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-16  7:46 UTC (permalink / raw)
  To: Ingo Molnar, linux-mtd
  Cc: Artem Bityutskiy, Linus Torvalds, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	Andrew Morton, David Woodhouse, Alan Cox

The core functionality is implemented as per Linus suggestion from

  http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html

(with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
been added which contains a callback to dump the kernel log buffers on
crashes. The kmsg_dump function gets called from oops_exit() and panic()
and invokes this callbacks with the crash reason.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
Reviewed-by: Ingo Molnar <mingo@elte.hu>
---
ChangeLog:
	* (Arjan van de Ven): Use EXPORT_SYMBOL_GPL
	* (Ingo Molnar): Switch list/spinlock definition order
	* (Ingo Molnar): Set/check ->registered within spinlocked region
	* (Ingo Molnar): Return error from unregister and check that the
	  dumper really is registered
	* (Ingo Molnar): Maximise constness and correct array check
	* (Ingo Molnar): Use _irqsave/_irqrestore also in kmsg_dump
	* (Ingo Molnar): Style fixes
	* (Anders Grafström): Correct kerneldoc names

 include/linux/kmsg_dump.h |   36 ++++++++++++++
 kernel/panic.c            |    3 +
 kernel/printk.c           |  116 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 155 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/kmsg_dump.h

diff --git a/include/linux/kmsg_dump.h b/include/linux/kmsg_dump.h
new file mode 100644
index 0000000..64296f3
--- /dev/null
+++ b/include/linux/kmsg_dump.h
@@ -0,0 +1,36 @@
+/*
+ * linux/include/kmsg_dump.h
+ *
+ * Copyright (C) 2009 Net Insight AB
+ *
+ * Author: Simon Kagstrom <simon.kagstrom@netinsight.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+#ifndef _LINUX_KMSG_DUMP_H
+#define _LINUX_KMSG_DUMP_H
+
+#include <linux/list.h>
+
+enum kmsg_dump_reason {
+	KMSG_DUMP_OOPS,
+	KMSG_DUMP_PANIC,
+};
+
+struct kmsg_dumper {
+	void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
+			const char *s1, unsigned long l1,
+			const char *s2, unsigned long l2);
+	struct list_head list;
+	int registered;
+};
+
+void kmsg_dump(enum kmsg_dump_reason reason);
+
+int kmsg_dump_register(struct kmsg_dumper *dumper);
+
+int kmsg_dump_unregister(struct kmsg_dumper *dumper);
+
+#endif /* _LINUX_DUMP_DEVICE_H */
diff --git a/kernel/panic.c b/kernel/panic.c
index c0b33b8..763296d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -10,6 +10,7 @@
  */
 #include <linux/debug_locks.h>
 #include <linux/interrupt.h>
+#include <linux/kmsg_dump.h>
 #include <linux/kallsyms.h>
 #include <linux/notifier.h>
 #include <linux/module.h>
@@ -76,6 +77,7 @@ NORET_TYPE void panic(const char * fmt, ...)
 	dump_stack();
 #endif
 
+	kmsg_dump(KMSG_DUMP_PANIC);
 	/*
 	 * If we have crashed and we have a crash kernel loaded let it handle
 	 * everything else.
@@ -341,6 +343,7 @@ void oops_exit(void)
 {
 	do_oops_enter_exit();
 	print_oops_end_marker();
+	kmsg_dump(KMSG_DUMP_OOPS);
 }
 
 #ifdef WANT_WARN_ON_SLOWPATH
diff --git a/kernel/printk.c b/kernel/printk.c
index f38b07f..d363306 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -33,6 +33,7 @@
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
+#include <linux/kmsg_dump.h>
 
 #include <asm/uaccess.h>
 
@@ -1405,3 +1406,118 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 }
 EXPORT_SYMBOL(printk_timed_ratelimit);
 #endif
+
+static DEFINE_SPINLOCK(dump_list_lock);
+static LIST_HEAD(dump_list);
+
+/**
+ *	kmsg_dump_register - register a kernel log dumper.
+ *	@dump: pointer to the kmsg_dumper structure
+ *
+ *	Adds a kernel log dumper to the system. The dump callback in the
+ *	structure will be called when the kernel oopses or panics and must be
+ *	set. Returns zero on success and -EINVAL or -EBUSY otherwise.
+ */
+int kmsg_dump_register(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	/* The dump callback needs to be set */
+	if (!dumper->dump)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+
+	/* Don't allow registering multiple times */
+	if (dumper->registered) {
+		spin_unlock_irqrestore(&dump_list_lock, flags);
+
+		return -EBUSY;
+	}
+
+	dumper->registered = 1;
+	list_add(&dumper->list, &dump_list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kmsg_dump_register);
+
+/**
+ *	kmsg_dump_unregister - unregister a kmsg dumper.
+ *	@dump: pointer to the kmsg_dumper structure
+ *
+ *	Removes a dump device from the system.
+ */
+int kmsg_dump_unregister(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	if (!dumper->registered) {
+		spin_unlock_irqrestore(&dump_list_lock, flags);
+
+		return -EINVAL;
+	}
+
+	dumper->registered = 0;
+	list_del(&dumper->list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
+
+static const char const *kmsg_reasons[] = {
+	[KMSG_DUMP_OOPS]	= "oops",
+	[KMSG_DUMP_PANIC]	= "panic",
+};
+
+static const char *kmsg_to_str(enum kmsg_dump_reason reason)
+{
+	if (reason >= ARRAY_SIZE(kmsg_reasons) || reason < 0)
+		return "unknown";
+
+	return kmsg_reasons[reason];
+}
+
+/**
+ *	kmsg_dump - dump kernel log to kernel message dumpers.
+ *	@reason: the reason (oops, panic etc) for dumping
+ *
+ *	Iterate through each of the dump devices and call the oops/panic
+ *	callbacks with the log buffer.
+ */
+void kmsg_dump(enum kmsg_dump_reason reason)
+{
+	unsigned long len = ACCESS_ONCE(log_end);
+	struct kmsg_dumper *dumper;
+	const char *s1, *s2;
+	unsigned long l1, l2;
+	unsigned long flags;
+
+	s1 = "";
+	l1 = 0;
+	s2 = log_buf;
+	l2 = len;
+
+	/* Have we rotated around the circular buffer? */
+	if (len > log_buf_len) {
+		unsigned long pos = len & LOG_BUF_MASK;
+
+		s1 = log_buf + pos;
+		l1 = log_buf_len - pos;
+
+		s2 = log_buf;
+		l2 = pos;
+	}
+
+	if (!spin_trylock_irqsave(&dump_list_lock, flags)) {
+		printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n",
+				kmsg_to_str(reason));
+		return;
+	}
+	list_for_each_entry(dumper, &dump_list, list)
+		dumper->dump(dumper, reason, s1, l1, s2, l2);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+}
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v9 5/5]: mtdoops: refactor as a kmsg_dumper
  2009-10-15 14:10   ` [PATCH v8 " Simon Kagstrom
@ 2009-10-16  7:46     ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-16  7:46 UTC (permalink / raw)
  To: linux-mtd; +Cc: David Woodhouse, Artem Bityutskiy

The last messages which happens before a crash might contain interesting
information about the crash. This patch reworks mtdoops using the
kmsg_dumper support instead of a console, which simplifies the code and
also includes the messages before the oops started.

On oops callbacks, the MTD device write is scheduled in a work queue (to
be able to use the regular mtd->write call), while panics call
mtd->panic_write directly. Thus, if panic_on_oops is set, the oops will
be written out during the panic.

A parameter to specify which mtd device to use (number or name), as well
as a flag, writable at runtime, to toggle wheter to dump oopses or only
panics (since oopses can often be handled by regular syslog).

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
---
ChangeLog:
	* Rebase against new P4
	* Check return values from kmsg_dump_register/unregister

 drivers/mtd/Kconfig   |    5 +-
 drivers/mtd/mtdoops.c |  219 +++++++++++++++++++++----------------------------
 2 files changed, 96 insertions(+), 128 deletions(-)

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index ecf90f5..60d6c31 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -312,8 +312,9 @@ config MTD_OOPS
 	  buffer in a flash partition where it can be read back at some
 	  later point.
 
-	  To use, add console=ttyMTDx to the kernel command line,
-	  where x is the MTD device number to use.
+	  To use, add mtddev=name/number to the kernel command line,
+	  where name/number is the name or number of the MTD device
+	  to use (e.g., mtddev=7 for /dev/mtd7).
 
 source "drivers/mtd/chips/Kconfig"
 
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 2870a11..709b351 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -29,18 +29,31 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/delay.h>
-#include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
+#include <linux/kmsg_dump.h>
 
 #define MTDOOPS_KERNMSG_MAGIC 0x5d005d00
+#define MTDOOPS_HEADER_SIZE   8
 
 static unsigned long record_size = 4096;
 module_param(record_size, ulong, 0400);
 MODULE_PARM_DESC(record_size,
 		"record size for MTD OOPS pages in bytes (default 4096)");
 
+static char mtddev[80];
+module_param_string(mtddev, mtddev, 80, 0400);
+MODULE_PARM_DESC(mtddev,
+		"name or index number of the MTD device to use");
+
+static int dump_oops = 1;
+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 struct mtdoops_context {
+	struct kmsg_dumper dump;
+
 	int mtd_index;
 	struct work_struct work_erase;
 	struct work_struct work_write;
@@ -49,14 +62,8 @@ static struct mtdoops_context {
 	int nextpage;
 	int nextcount;
 	unsigned long *oops_page_used;
-	char *name;
 
 	void *oops_buf;
-
-	/* writecount and disabling ready are spin lock protected */
-	spinlock_t writecount_lock;
-	int ready;
-	int writecount;
 } oops_cxt;
 
 static void mark_page_used(struct mtdoops_context *cxt, int page)
@@ -108,7 +115,7 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
 		remove_wait_queue(&wait_q, &wait);
 		printk(KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] on \"%s\" failed\n",
 		       (unsigned long long)erase.addr,
-		       (unsigned long long)erase.len, mtd->name);
+		       (unsigned long long)erase.len, mtddev);
 		return ret;
 	}
 
@@ -138,7 +145,6 @@ static void mtdoops_inc_counter(struct mtdoops_context *cxt)
 
 	printk(KERN_DEBUG "mtdoops: ready %d, %d (no erase)\n",
 	       cxt->nextpage, cxt->nextcount);
-	cxt->ready = 1;
 }
 
 /* Scheduled work - when we can't proceed without erasing a block */
@@ -187,7 +193,6 @@ badblock:
 	if (ret >= 0) {
 		printk(KERN_DEBUG "mtdoops: ready %d, %d\n",
 		       cxt->nextpage, cxt->nextcount);
-		cxt->ready = 1;
 		return;
 	}
 
@@ -205,11 +210,13 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 {
 	struct mtd_info *mtd = cxt->mtd;
 	size_t retlen;
+	u32 *hdr;
 	int ret;
 
-	if (cxt->writecount < record_size)
-		memset(cxt->oops_buf + cxt->writecount, 0xff,
-					record_size - cxt->writecount);
+	/* Add mtdoops header to the buffer */
+	hdr = cxt->oops_buf;
+	hdr[0] = cxt->nextcount;
+	hdr[1] = MTDOOPS_KERNMSG_MAGIC;
 
 	if (panic)
 		ret = mtd->panic_write(mtd, cxt->nextpage * record_size,
@@ -218,17 +225,15 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 		ret = mtd->write(mtd, cxt->nextpage * record_size,
 					record_size, &retlen, cxt->oops_buf);
 
-	cxt->writecount = 0;
-
 	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);
 	mark_page_used(cxt, cxt->nextpage);
+	memset(cxt->oops_buf, 0xff, record_size);
 
 	mtdoops_inc_counter(cxt);
 }
 
-
 static void mtdoops_workfunc_write(struct work_struct *work)
 {
 	struct mtdoops_context *cxt =
@@ -247,10 +252,13 @@ static void find_next_position(struct mtdoops_context *cxt)
 	for (page = 0; page < cxt->oops_pages; page++) {
 		/* Assume the page is used */
 		mark_page_used(cxt, page);
-		ret = mtd->read(mtd, page * record_size, 8, &retlen, (u_char *) &count[0]);
-		if (retlen != 8 || (ret < 0 && ret != -EUCLEAN)) {
-			printk(KERN_ERR "mtdoops: read failure at %ld (%td of 8 read), err %d\n",
-			       page * record_size, retlen, ret);
+		ret = mtd->read(mtd, page * record_size, MTDOOPS_HEADER_SIZE,
+				&retlen, (u_char *) &count[0]);
+		if (retlen != MTDOOPS_HEADER_SIZE ||
+				(ret < 0 && ret != -EUCLEAN)) {
+			printk(KERN_ERR "mtdoops: read failure at %ld (%td of %d read), err %d\n",
+			       page * record_size, retlen,
+			       MTDOOPS_HEADER_SIZE, ret);
 			continue;
 		}
 
@@ -287,7 +295,6 @@ static void find_next_position(struct mtdoops_context *cxt)
 		} else {
 			printk(KERN_DEBUG "mtdoops: ready %d, %d (clean)\n",
 			       cxt->nextpage, cxt->nextcount);
-			cxt->ready = 1;
 		}
 		return;
 	}
@@ -298,6 +305,42 @@ 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)
+{
+	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;
+
+	/* 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;
+
+	memcpy(dst, s1 + s1_start, l1_cpy);
+	memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
+
+	/* Panics must be written immediately */
+	if (reason == KMSG_DUMP_PANIC) {
+		if (!cxt->mtd->panic_write)
+			printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n");
+		else
+			mtdoops_write(cxt, 1);
+		return;
+	}
+
+	/* For other cases, schedule work to write it "nicely" */
+	schedule_work(&cxt->work_write);
+}
 
 static void mtdoops_notify_add(struct mtd_info *mtd)
 {
@@ -306,7 +349,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 
 	do_div(mtdoops_pages, record_size);
 
-	if (cxt->name && !strcmp(mtd->name, cxt->name))
+	if (!strcmp(mtd->name, mtddev))
 		cxt->mtd_index = mtd->index;
 
 	if (mtd->index != cxt->mtd_index || cxt->mtd_index < 0)
@@ -331,6 +374,14 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		printk(KERN_ERR "Could not allocate page array\n");
 		return;
 	}
+	cxt->dump.dump = mtdoops_do_dump;
+	if (kmsg_dump_register(&cxt->dump) < 0) {
+		printk(KERN_ERR "Registering kmsg dumper failed\n");
+		vfree(cxt->oops_page_used);
+		cxt->oops_page_used = NULL;
+		return;
+	}
+
 	cxt->mtd = mtd;
 	if (mtd->size > INT_MAX)
 		cxt->oops_pages = INT_MAX / record_size;
@@ -349,116 +400,29 @@ 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 "Could not unregister kmsg_dumper??\n");
+
 	cxt->mtd = NULL;
 	flush_scheduled_work();
 }
 
-static void mtdoops_console_sync(void)
-{
-	struct mtdoops_context *cxt = &oops_cxt;
-	struct mtd_info *mtd = cxt->mtd;
-	unsigned long flags;
-
-	if (!cxt->ready || !mtd || cxt->writecount == 0)
-		return;
-
-	/*
-	 *  Once ready is 0 and we've held the lock no further writes to the
-	 *  buffer will happen
-	 */
-	spin_lock_irqsave(&cxt->writecount_lock, flags);
-	if (!cxt->ready) {
-		spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-		return;
-	}
-	cxt->ready = 0;
-	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-
-	if (mtd->panic_write && (in_interrupt() || panic_on_oops))
-		/* Interrupt context, we're going to panic so try and log */
-		mtdoops_write(cxt, 1);
-	else
-		schedule_work(&cxt->work_write);
-}
-
-static void
-mtdoops_console_write(struct console *co, const char *s, unsigned int count)
-{
-	struct mtdoops_context *cxt = co->data;
-	struct mtd_info *mtd = cxt->mtd;
-	unsigned long flags;
-
-	if (!oops_in_progress) {
-		mtdoops_console_sync();
-		return;
-	}
-
-	if (!cxt->ready || !mtd)
-		return;
-
-	/* Locking on writecount ensures sequential writes to the buffer */
-	spin_lock_irqsave(&cxt->writecount_lock, flags);
-
-	/* Check ready status didn't change whilst waiting for the lock */
-	if (!cxt->ready) {
-		spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-		return;
-	}
-
-	if (cxt->writecount == 0) {
-		u32 *stamp = cxt->oops_buf;
-		*stamp++ = cxt->nextcount;
-		*stamp = MTDOOPS_KERNMSG_MAGIC;
-		cxt->writecount = 8;
-	}
-
-	if (count + cxt->writecount > record_size)
-		count = record_size - cxt->writecount;
-
-	memcpy(cxt->oops_buf + cxt->writecount, s, count);
-	cxt->writecount += count;
-
-	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-
-	if (cxt->writecount == record_size)
-		mtdoops_console_sync();
-}
-
-static int __init mtdoops_console_setup(struct console *co, char *options)
-{
-	struct mtdoops_context *cxt = co->data;
-
-	if (cxt->mtd_index != -1 || cxt->name)
-		return -EBUSY;
-	if (options) {
-		cxt->name = kstrdup(options, GFP_KERNEL);
-		return 0;
-	}
-	if (co->index == -1)
-		return -EINVAL;
-
-	cxt->mtd_index = co->index;
-	return 0;
-}
 
 static struct mtd_notifier mtdoops_notifier = {
 	.add	= mtdoops_notify_add,
 	.remove	= mtdoops_notify_remove,
 };
 
-static struct console mtdoops_console = {
-	.name		= "ttyMTD",
-	.write		= mtdoops_console_write,
-	.setup		= mtdoops_console_setup,
-	.unblank	= mtdoops_console_sync,
-	.index		= -1,
-	.data		= &oops_cxt,
-};
-
-static int __init mtdoops_console_init(void)
+static int __init mtdoops_init(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
+	int mtd_index;
+	char *endp;
 
+	if (strlen(mtddev) == 0) {
+		printk(KERN_ERR "mtdoops: mtd device (mtddev=name/number) must be supplied\n");
+		return -EINVAL;
+	}
 	if ((record_size & 4095) != 0) {
 		printk(KERN_ERR "mtdoops: record_size must be a multiple of 4096\n");
 		return -EINVAL;
@@ -467,36 +431,39 @@ static int __init mtdoops_console_init(void)
 		printk(KERN_ERR "mtdoops: record_size must be over 4096 bytes\n");
 		return -EINVAL;
 	}
+
+	/* Setup the MTD device to use */
 	cxt->mtd_index = -1;
+	mtd_index = simple_strtoul(mtddev, &endp, 0);
+	if (endp != mtddev)
+		cxt->mtd_index = mtd_index;
+
 	cxt->oops_buf = vmalloc(record_size);
 	if (!cxt->oops_buf) {
 		printk(KERN_ERR "mtdoops: failed to allocate buffer workspace\n");
 		return -ENOMEM;
 	}
+	memset(cxt->oops_buf, 0xff, record_size);
 
-	spin_lock_init(&cxt->writecount_lock);
 	INIT_WORK(&cxt->work_erase, mtdoops_workfunc_erase);
 	INIT_WORK(&cxt->work_write, mtdoops_workfunc_write);
 
-	register_console(&mtdoops_console);
 	register_mtd_user(&mtdoops_notifier);
 	return 0;
 }
 
-static void __exit mtdoops_console_exit(void)
+static void __exit mtdoops_exit(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
 
 	unregister_mtd_user(&mtdoops_notifier);
-	unregister_console(&mtdoops_console);
-	kfree(cxt->name);
 	vfree(cxt->oops_buf);
 	vfree(cxt->oops_page_used);
 }
 
 
-subsys_initcall(mtdoops_console_init);
-module_exit(mtdoops_console_exit);
+module_init(mtdoops_init);
+module_exit(mtdoops_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* Re: [PATCH v9 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-16  7:46           ` Simon Kagstrom
@ 2009-10-16  8:09             ` Ingo Molnar
  -1 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-16  8:09 UTC (permalink / raw)
  To: Simon Kagstrom
  Cc: linux-mtd, Linus Torvalds, Artem Bityutskiy, David Woodhouse,
	Andrew Morton, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox


* Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:

/**
 *	kmsg_dump_register - register a kernel log dumper.
 *	@dump: pointer to the kmsg_dumper structure
 *
 *	Adds a kernel log dumper to the system. The dump callback in the
 *	structure will be called when the kernel oopses or panics and must be
 *	set. Returns zero on success and -EINVAL or -EBUSY otherwise.
 */

Small detail - please use the KernelDoc style used in existing printk.c 
facilities, i.e. use a single space instead of a tab:

/**
 * kmsg_dump_register - register a kernel log dumper.
 * @dump: pointer to the kmsg_dumper structure
 *
 * Adds a kernel log dumper to the system. The dump callback in the
 * structure will be called when the kernel oopses or panics and must be
 * set. Returns zero on success and -EINVAL or -EBUSY otherwise.
 */

(in the other functions as well)

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v9 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-16  8:09             ` Ingo Molnar
  0 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-16  8:09 UTC (permalink / raw)
  To: Simon Kagstrom
  Cc: Artem Bityutskiy, David Woodhouse, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Andrew Morton, Linus Torvalds, Alan Cox


* Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:

/**
 *	kmsg_dump_register - register a kernel log dumper.
 *	@dump: pointer to the kmsg_dumper structure
 *
 *	Adds a kernel log dumper to the system. The dump callback in the
 *	structure will be called when the kernel oopses or panics and must be
 *	set. Returns zero on success and -EINVAL or -EBUSY otherwise.
 */

Small detail - please use the KernelDoc style used in existing printk.c 
facilities, i.e. use a single space instead of a tab:

/**
 * kmsg_dump_register - register a kernel log dumper.
 * @dump: pointer to the kmsg_dumper structure
 *
 * Adds a kernel log dumper to the system. The dump callback in the
 * structure will be called when the kernel oopses or panics and must be
 * set. Returns zero on success and -EINVAL or -EBUSY otherwise.
 */

(in the other functions as well)

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v9 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-16  8:09             ` Ingo Molnar
@ 2009-10-16  8:24               ` Artem Bityutskiy
  -1 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-16  8:24 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Simon Kagstrom, linux-mtd, Linus Torvalds, David Woodhouse,
	Andrew Morton, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

On Fri, 2009-10-16 at 10:09 +0200, Ingo Molnar wrote:
> * Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:
> 
> /**
>  *	kmsg_dump_register - register a kernel log dumper.
>  *	@dump: pointer to the kmsg_dumper structure
>  *
>  *	Adds a kernel log dumper to the system. The dump callback in the
>  *	structure will be called when the kernel oopses or panics and must be
>  *	set. Returns zero on success and -EINVAL or -EBUSY otherwise.
>  */
> 
> Small detail - please use the KernelDoc style used in existing printk.c 
> facilities, i.e. use a single space instead of a tab:
> 
> /**
>  * kmsg_dump_register - register a kernel log dumper.
>  * @dump: pointer to the kmsg_dumper structure
>  *
>  * Adds a kernel log dumper to the system. The dump callback in the
>  * structure will be called when the kernel oopses or panics and must be
>  * set. Returns zero on success and -EINVAL or -EBUSY otherwise.
>  */

And then %-EINVAL and %-EBUSY.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v9 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-16  8:24               ` Artem Bityutskiy
  0 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-16  8:24 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: David Woodhouse, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Simon Kagstrom, Andrew Morton, Linus Torvalds,
	Alan Cox

On Fri, 2009-10-16 at 10:09 +0200, Ingo Molnar wrote:
> * Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:
> 
> /**
>  *	kmsg_dump_register - register a kernel log dumper.
>  *	@dump: pointer to the kmsg_dumper structure
>  *
>  *	Adds a kernel log dumper to the system. The dump callback in the
>  *	structure will be called when the kernel oopses or panics and must be
>  *	set. Returns zero on success and -EINVAL or -EBUSY otherwise.
>  */
> 
> Small detail - please use the KernelDoc style used in existing printk.c 
> facilities, i.e. use a single space instead of a tab:
> 
> /**
>  * kmsg_dump_register - register a kernel log dumper.
>  * @dump: pointer to the kmsg_dumper structure
>  *
>  * Adds a kernel log dumper to the system. The dump callback in the
>  * structure will be called when the kernel oopses or panics and must be
>  * set. Returns zero on success and -EINVAL or -EBUSY otherwise.
>  */

And then %-EINVAL and %-EBUSY.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v10 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-16  8:24               ` Artem Bityutskiy
@ 2009-10-16  9:25                 ` Simon Kagstrom
  -1 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-16  9:25 UTC (permalink / raw)
  To: dedekind1, Ingo Molnar, linux-mtd
  Cc: Linus Torvalds, David Woodhouse, Andrew Morton, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

The core functionality is implemented as per Linus suggestion from

  http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html

(with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
been added which contains a callback to dump the kernel log buffers on
crashes. The kmsg_dump function gets called from oops_exit() and panic()
and invokes this callbacks with the crash reason.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
Reviewed-by: Ingo Molnar <mingo@elte.hu>
---
ChangeLog:
	* (Ingo Molnar): tabs->spaces in KernelDoc comments
	* (Artem Bityutskiy): %-EINVAL
	* (me): Add KernelDoc for the structure as well

 include/linux/kmsg_dump.h |   44 +++++++++++++++++
 kernel/panic.c            |    3 +
 kernel/printk.c           |  117 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 164 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/kmsg_dump.h

diff --git a/include/linux/kmsg_dump.h b/include/linux/kmsg_dump.h
new file mode 100644
index 0000000..27d3aec
--- /dev/null
+++ b/include/linux/kmsg_dump.h
@@ -0,0 +1,44 @@
+/*
+ * linux/include/kmsg_dump.h
+ *
+ * Copyright (C) 2009 Net Insight AB
+ *
+ * Author: Simon Kagstrom <simon.kagstrom@netinsight.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+#ifndef _LINUX_KMSG_DUMP_H
+#define _LINUX_KMSG_DUMP_H
+
+#include <linux/list.h>
+
+enum kmsg_dump_reason {
+	KMSG_DUMP_OOPS,
+	KMSG_DUMP_PANIC,
+};
+
+/**
+ * struct kmsg_dumper - kernel crash message dumper structure
+ * @dump:	The callback which gets called on crashes. The buffer is passed
+ * 		as two sections, where s1 (length l1) contains the older
+ * 		messages and s2 (length l2) contains the newer.
+ * @list:	Entry in the dumper list (private)
+ * @registered:	Flag that specifies if this is already registered
+ */
+struct kmsg_dumper {
+	void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
+			const char *s1, unsigned long l1,
+			const char *s2, unsigned long l2);
+	struct list_head list;
+	int registered;
+};
+
+void kmsg_dump(enum kmsg_dump_reason reason);
+
+int kmsg_dump_register(struct kmsg_dumper *dumper);
+
+int kmsg_dump_unregister(struct kmsg_dumper *dumper);
+
+#endif /* _LINUX_DUMP_DEVICE_H */
diff --git a/kernel/panic.c b/kernel/panic.c
index c0b33b8..763296d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -10,6 +10,7 @@
  */
 #include <linux/debug_locks.h>
 #include <linux/interrupt.h>
+#include <linux/kmsg_dump.h>
 #include <linux/kallsyms.h>
 #include <linux/notifier.h>
 #include <linux/module.h>
@@ -76,6 +77,7 @@ NORET_TYPE void panic(const char * fmt, ...)
 	dump_stack();
 #endif
 
+	kmsg_dump(KMSG_DUMP_PANIC);
 	/*
 	 * If we have crashed and we have a crash kernel loaded let it handle
 	 * everything else.
@@ -341,6 +343,7 @@ void oops_exit(void)
 {
 	do_oops_enter_exit();
 	print_oops_end_marker();
+	kmsg_dump(KMSG_DUMP_OOPS);
 }
 
 #ifdef WANT_WARN_ON_SLOWPATH
diff --git a/kernel/printk.c b/kernel/printk.c
index f38b07f..59116be 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -33,6 +33,7 @@
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
+#include <linux/kmsg_dump.h>
 
 #include <asm/uaccess.h>
 
@@ -1405,3 +1406,119 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 }
 EXPORT_SYMBOL(printk_timed_ratelimit);
 #endif
+
+static DEFINE_SPINLOCK(dump_list_lock);
+static LIST_HEAD(dump_list);
+
+/**
+ * kmsg_dump_register - register a kernel log dumper.
+ * @dump: pointer to the kmsg_dumper structure
+ *
+ * Adds a kernel log dumper to the system. The dump callback in the
+ * structure will be called when the kernel oopses or panics and must be
+ * set. Returns zero on success and %-EINVAL or %-EBUSY otherwise.
+ */
+int kmsg_dump_register(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	/* The dump callback needs to be set */
+	if (!dumper->dump)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+
+	/* Don't allow registering multiple times */
+	if (dumper->registered) {
+		spin_unlock_irqrestore(&dump_list_lock, flags);
+
+		return -EBUSY;
+	}
+
+	dumper->registered = 1;
+	list_add(&dumper->list, &dump_list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kmsg_dump_register);
+
+/**
+ * kmsg_dump_unregister - unregister a kmsg dumper.
+ * @dump: pointer to the kmsg_dumper structure
+ *
+ * Removes a dump device from the system. Returns zero on success and
+ * %-EINVAL otherwise.
+ */
+int kmsg_dump_unregister(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	if (!dumper->registered) {
+		spin_unlock_irqrestore(&dump_list_lock, flags);
+
+		return -EINVAL;
+	}
+
+	dumper->registered = 0;
+	list_del(&dumper->list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
+
+static const char const *kmsg_reasons[] = {
+	[KMSG_DUMP_OOPS]	= "oops",
+	[KMSG_DUMP_PANIC]	= "panic",
+};
+
+static const char *kmsg_to_str(enum kmsg_dump_reason reason)
+{
+	if (reason >= ARRAY_SIZE(kmsg_reasons) || reason < 0)
+		return "unknown";
+
+	return kmsg_reasons[reason];
+}
+
+/**
+ * kmsg_dump - dump kernel log to kernel message dumpers.
+ * @reason: the reason (oops, panic etc) for dumping
+ *
+ * Iterate through each of the dump devices and call the oops/panic
+ * callbacks with the log buffer.
+ */
+void kmsg_dump(enum kmsg_dump_reason reason)
+{
+	unsigned long len = ACCESS_ONCE(log_end);
+	struct kmsg_dumper *dumper;
+	const char *s1, *s2;
+	unsigned long l1, l2;
+	unsigned long flags;
+
+	s1 = "";
+	l1 = 0;
+	s2 = log_buf;
+	l2 = len;
+
+	/* Have we rotated around the circular buffer? */
+	if (len > log_buf_len) {
+		unsigned long pos = len & LOG_BUF_MASK;
+
+		s1 = log_buf + pos;
+		l1 = log_buf_len - pos;
+
+		s2 = log_buf;
+		l2 = pos;
+	}
+
+	if (!spin_trylock_irqsave(&dump_list_lock, flags)) {
+		printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n",
+				kmsg_to_str(reason));
+		return;
+	}
+	list_for_each_entry(dumper, &dump_list, list)
+		dumper->dump(dumper, reason, s1, l1, s2, l2);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+}
-- 
1.6.0.4


^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v10 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-16  9:25                 ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-16  9:25 UTC (permalink / raw)
  To: dedekind1, Ingo Molnar, linux-mtd
  Cc: Linus Torvalds, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Andrew Morton, David Woodhouse, Alan Cox

The core functionality is implemented as per Linus suggestion from

  http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html

(with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
been added which contains a callback to dump the kernel log buffers on
crashes. The kmsg_dump function gets called from oops_exit() and panic()
and invokes this callbacks with the crash reason.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
Reviewed-by: Ingo Molnar <mingo@elte.hu>
---
ChangeLog:
	* (Ingo Molnar): tabs->spaces in KernelDoc comments
	* (Artem Bityutskiy): %-EINVAL
	* (me): Add KernelDoc for the structure as well

 include/linux/kmsg_dump.h |   44 +++++++++++++++++
 kernel/panic.c            |    3 +
 kernel/printk.c           |  117 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 164 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/kmsg_dump.h

diff --git a/include/linux/kmsg_dump.h b/include/linux/kmsg_dump.h
new file mode 100644
index 0000000..27d3aec
--- /dev/null
+++ b/include/linux/kmsg_dump.h
@@ -0,0 +1,44 @@
+/*
+ * linux/include/kmsg_dump.h
+ *
+ * Copyright (C) 2009 Net Insight AB
+ *
+ * Author: Simon Kagstrom <simon.kagstrom@netinsight.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+#ifndef _LINUX_KMSG_DUMP_H
+#define _LINUX_KMSG_DUMP_H
+
+#include <linux/list.h>
+
+enum kmsg_dump_reason {
+	KMSG_DUMP_OOPS,
+	KMSG_DUMP_PANIC,
+};
+
+/**
+ * struct kmsg_dumper - kernel crash message dumper structure
+ * @dump:	The callback which gets called on crashes. The buffer is passed
+ * 		as two sections, where s1 (length l1) contains the older
+ * 		messages and s2 (length l2) contains the newer.
+ * @list:	Entry in the dumper list (private)
+ * @registered:	Flag that specifies if this is already registered
+ */
+struct kmsg_dumper {
+	void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
+			const char *s1, unsigned long l1,
+			const char *s2, unsigned long l2);
+	struct list_head list;
+	int registered;
+};
+
+void kmsg_dump(enum kmsg_dump_reason reason);
+
+int kmsg_dump_register(struct kmsg_dumper *dumper);
+
+int kmsg_dump_unregister(struct kmsg_dumper *dumper);
+
+#endif /* _LINUX_DUMP_DEVICE_H */
diff --git a/kernel/panic.c b/kernel/panic.c
index c0b33b8..763296d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -10,6 +10,7 @@
  */
 #include <linux/debug_locks.h>
 #include <linux/interrupt.h>
+#include <linux/kmsg_dump.h>
 #include <linux/kallsyms.h>
 #include <linux/notifier.h>
 #include <linux/module.h>
@@ -76,6 +77,7 @@ NORET_TYPE void panic(const char * fmt, ...)
 	dump_stack();
 #endif
 
+	kmsg_dump(KMSG_DUMP_PANIC);
 	/*
 	 * If we have crashed and we have a crash kernel loaded let it handle
 	 * everything else.
@@ -341,6 +343,7 @@ void oops_exit(void)
 {
 	do_oops_enter_exit();
 	print_oops_end_marker();
+	kmsg_dump(KMSG_DUMP_OOPS);
 }
 
 #ifdef WANT_WARN_ON_SLOWPATH
diff --git a/kernel/printk.c b/kernel/printk.c
index f38b07f..59116be 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -33,6 +33,7 @@
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
+#include <linux/kmsg_dump.h>
 
 #include <asm/uaccess.h>
 
@@ -1405,3 +1406,119 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 }
 EXPORT_SYMBOL(printk_timed_ratelimit);
 #endif
+
+static DEFINE_SPINLOCK(dump_list_lock);
+static LIST_HEAD(dump_list);
+
+/**
+ * kmsg_dump_register - register a kernel log dumper.
+ * @dump: pointer to the kmsg_dumper structure
+ *
+ * Adds a kernel log dumper to the system. The dump callback in the
+ * structure will be called when the kernel oopses or panics and must be
+ * set. Returns zero on success and %-EINVAL or %-EBUSY otherwise.
+ */
+int kmsg_dump_register(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	/* The dump callback needs to be set */
+	if (!dumper->dump)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+
+	/* Don't allow registering multiple times */
+	if (dumper->registered) {
+		spin_unlock_irqrestore(&dump_list_lock, flags);
+
+		return -EBUSY;
+	}
+
+	dumper->registered = 1;
+	list_add(&dumper->list, &dump_list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kmsg_dump_register);
+
+/**
+ * kmsg_dump_unregister - unregister a kmsg dumper.
+ * @dump: pointer to the kmsg_dumper structure
+ *
+ * Removes a dump device from the system. Returns zero on success and
+ * %-EINVAL otherwise.
+ */
+int kmsg_dump_unregister(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	if (!dumper->registered) {
+		spin_unlock_irqrestore(&dump_list_lock, flags);
+
+		return -EINVAL;
+	}
+
+	dumper->registered = 0;
+	list_del(&dumper->list);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
+
+static const char const *kmsg_reasons[] = {
+	[KMSG_DUMP_OOPS]	= "oops",
+	[KMSG_DUMP_PANIC]	= "panic",
+};
+
+static const char *kmsg_to_str(enum kmsg_dump_reason reason)
+{
+	if (reason >= ARRAY_SIZE(kmsg_reasons) || reason < 0)
+		return "unknown";
+
+	return kmsg_reasons[reason];
+}
+
+/**
+ * kmsg_dump - dump kernel log to kernel message dumpers.
+ * @reason: the reason (oops, panic etc) for dumping
+ *
+ * Iterate through each of the dump devices and call the oops/panic
+ * callbacks with the log buffer.
+ */
+void kmsg_dump(enum kmsg_dump_reason reason)
+{
+	unsigned long len = ACCESS_ONCE(log_end);
+	struct kmsg_dumper *dumper;
+	const char *s1, *s2;
+	unsigned long l1, l2;
+	unsigned long flags;
+
+	s1 = "";
+	l1 = 0;
+	s2 = log_buf;
+	l2 = len;
+
+	/* Have we rotated around the circular buffer? */
+	if (len > log_buf_len) {
+		unsigned long pos = len & LOG_BUF_MASK;
+
+		s1 = log_buf + pos;
+		l1 = log_buf_len - pos;
+
+		s2 = log_buf;
+		l2 = pos;
+	}
+
+	if (!spin_trylock_irqsave(&dump_list_lock, flags)) {
+		printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n",
+				kmsg_to_str(reason));
+		return;
+	}
+	list_for_each_entry(dumper, &dump_list, list)
+		dumper->dump(dumper, reason, s1, l1, s2, l2);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+}
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* Re: [PATCH v10 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-16  9:25                 ` Simon Kagstrom
@ 2009-10-16 10:10                   ` Ingo Molnar
  -1 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-16 10:10 UTC (permalink / raw)
  To: Simon Kagstrom
  Cc: dedekind1, linux-mtd, Linus Torvalds, David Woodhouse,
	Andrew Morton, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox


* Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:

> +int kmsg_dump_register(struct kmsg_dumper *dumper)
> +{
> +	unsigned long flags;
> +
> +	/* The dump callback needs to be set */
> +	if (!dumper->dump)
> +		return -EINVAL;
> +
> +	spin_lock_irqsave(&dump_list_lock, flags);
> +
> +	/* Don't allow registering multiple times */
> +	if (dumper->registered) {
> +		spin_unlock_irqrestore(&dump_list_lock, flags);
> +
> +		return -EBUSY;
> +	}
> +
> +	dumper->registered = 1;
> +	list_add(&dumper->list, &dump_list);
> +	spin_unlock_irqrestore(&dump_list_lock, flags);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(kmsg_dump_register);


i dont want to bikeshed paint this but this sequence caught my eyes. We 
generally do flatter and clearer locking sequences:

int kmsg_dump_register(struct kmsg_dumper *dumper)
{
	unsigned long flags;
	int err = -EBUSY;

	/* The dump callback needs to be set */
	if (!dumper->dump)
		return -EINVAL;

	spin_lock_irqsave(&dump_list_lock, flags);

	/* Don't allow registering multiple times */
	if (!dumper->registered) {
		dumper->registered = 1;
		list_add_tail(&dumper->list, &dump_list);
		err = 0;
	}

	spin_unlock_irqrestore(&dump_list_lock, flags);

	return err;
}
EXPORT_SYMBOL_GPL(kmsg_dump_register);

(warning: untested, written in mail editor)

Same goes for kmsg_dump_unregister().

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v10 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-16 10:10                   ` Ingo Molnar
  0 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-16 10:10 UTC (permalink / raw)
  To: Simon Kagstrom
  Cc: dedekind1, David Woodhouse, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Andrew Morton, Linus Torvalds, Alan Cox


* Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:

> +int kmsg_dump_register(struct kmsg_dumper *dumper)
> +{
> +	unsigned long flags;
> +
> +	/* The dump callback needs to be set */
> +	if (!dumper->dump)
> +		return -EINVAL;
> +
> +	spin_lock_irqsave(&dump_list_lock, flags);
> +
> +	/* Don't allow registering multiple times */
> +	if (dumper->registered) {
> +		spin_unlock_irqrestore(&dump_list_lock, flags);
> +
> +		return -EBUSY;
> +	}
> +
> +	dumper->registered = 1;
> +	list_add(&dumper->list, &dump_list);
> +	spin_unlock_irqrestore(&dump_list_lock, flags);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(kmsg_dump_register);


i dont want to bikeshed paint this but this sequence caught my eyes. We 
generally do flatter and clearer locking sequences:

int kmsg_dump_register(struct kmsg_dumper *dumper)
{
	unsigned long flags;
	int err = -EBUSY;

	/* The dump callback needs to be set */
	if (!dumper->dump)
		return -EINVAL;

	spin_lock_irqsave(&dump_list_lock, flags);

	/* Don't allow registering multiple times */
	if (!dumper->registered) {
		dumper->registered = 1;
		list_add_tail(&dumper->list, &dump_list);
		err = 0;
	}

	spin_unlock_irqrestore(&dump_list_lock, flags);

	return err;
}
EXPORT_SYMBOL_GPL(kmsg_dump_register);

(warning: untested, written in mail editor)

Same goes for kmsg_dump_unregister().

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v10 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-16 10:10                   ` Ingo Molnar
@ 2009-10-16 11:00                     ` Artem Bityutskiy
  -1 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-16 11:00 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Simon Kagstrom, linux-mtd, Linus Torvalds, David Woodhouse,
	Andrew Morton, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

On Fri, 2009-10-16 at 12:10 +0200, Ingo Molnar wrote:
> * Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:
> 
> > +int kmsg_dump_register(struct kmsg_dumper *dumper)
> > +{
> > +	unsigned long flags;
> > +
> > +	/* The dump callback needs to be set */
> > +	if (!dumper->dump)
> > +		return -EINVAL;
> > +
> > +	spin_lock_irqsave(&dump_list_lock, flags);
> > +
> > +	/* Don't allow registering multiple times */
> > +	if (dumper->registered) {
> > +		spin_unlock_irqrestore(&dump_list_lock, flags);
> > +
> > +		return -EBUSY;
> > +	}
> > +
> > +	dumper->registered = 1;
> > +	list_add(&dumper->list, &dump_list);
> > +	spin_unlock_irqrestore(&dump_list_lock, flags);
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(kmsg_dump_register);
> 
> 
> i dont want to bikeshed paint this but this sequence caught my eyes. We 
> generally do flatter and clearer locking sequences:
> 
> int kmsg_dump_register(struct kmsg_dumper *dumper)
> {
> 	unsigned long flags;
> 	int err = -EBUSY;
> 
> 	/* The dump callback needs to be set */
> 	if (!dumper->dump)
> 		return -EINVAL;
> 
> 	spin_lock_irqsave(&dump_list_lock, flags);
> 
> 	/* Don't allow registering multiple times */
> 	if (!dumper->registered) {
> 		dumper->registered = 1;
> 		list_add_tail(&dumper->list, &dump_list);
> 		err = 0;
> 	}
> 
> 	spin_unlock_irqrestore(&dump_list_lock, flags);
> 
> 	return err;
> }
> EXPORT_SYMBOL_GPL(kmsg_dump_register);

And while we are on it, I think these extra lines before and after
spinlocks are unneeded and even a bit annoying :-)

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v10 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-16 11:00                     ` Artem Bityutskiy
  0 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-16 11:00 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: David Woodhouse, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Simon Kagstrom, Andrew Morton, Linus Torvalds,
	Alan Cox

On Fri, 2009-10-16 at 12:10 +0200, Ingo Molnar wrote:
> * Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:
> 
> > +int kmsg_dump_register(struct kmsg_dumper *dumper)
> > +{
> > +	unsigned long flags;
> > +
> > +	/* The dump callback needs to be set */
> > +	if (!dumper->dump)
> > +		return -EINVAL;
> > +
> > +	spin_lock_irqsave(&dump_list_lock, flags);
> > +
> > +	/* Don't allow registering multiple times */
> > +	if (dumper->registered) {
> > +		spin_unlock_irqrestore(&dump_list_lock, flags);
> > +
> > +		return -EBUSY;
> > +	}
> > +
> > +	dumper->registered = 1;
> > +	list_add(&dumper->list, &dump_list);
> > +	spin_unlock_irqrestore(&dump_list_lock, flags);
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(kmsg_dump_register);
> 
> 
> i dont want to bikeshed paint this but this sequence caught my eyes. We 
> generally do flatter and clearer locking sequences:
> 
> int kmsg_dump_register(struct kmsg_dumper *dumper)
> {
> 	unsigned long flags;
> 	int err = -EBUSY;
> 
> 	/* The dump callback needs to be set */
> 	if (!dumper->dump)
> 		return -EINVAL;
> 
> 	spin_lock_irqsave(&dump_list_lock, flags);
> 
> 	/* Don't allow registering multiple times */
> 	if (!dumper->registered) {
> 		dumper->registered = 1;
> 		list_add_tail(&dumper->list, &dump_list);
> 		err = 0;
> 	}
> 
> 	spin_unlock_irqrestore(&dump_list_lock, flags);
> 
> 	return err;
> }
> EXPORT_SYMBOL_GPL(kmsg_dump_register);

And while we are on it, I think these extra lines before and after
spinlocks are unneeded and even a bit annoying :-)

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v10 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-16  9:25                 ` Simon Kagstrom
@ 2009-10-16 11:25                   ` Aaro Koskinen
  -1 siblings, 0 replies; 94+ messages in thread
From: Aaro Koskinen @ 2009-10-16 11:25 UTC (permalink / raw)
  To: ext Simon Kagstrom
  Cc: dedekind1, Ingo Molnar, linux-mtd, Linus Torvalds,
	David Woodhouse, Andrew Morton, LKML, Alan Cox

Hello,

Simon Kagstrom wrote:
> +#ifndef _LINUX_KMSG_DUMP_H
> +#define _LINUX_KMSG_DUMP_H
> +
> +#include <linux/list.h>
> +
> +enum kmsg_dump_reason {
> +	KMSG_DUMP_OOPS,
> +	KMSG_DUMP_PANIC,
> +};
> +
> +/**
> + * struct kmsg_dumper - kernel crash message dumper structure
> + * @dump:	The callback which gets called on crashes. The buffer is passed
> + * 		as two sections, where s1 (length l1) contains the older
> + * 		messages and s2 (length l2) contains the newer.
> + * @list:	Entry in the dumper list (private)
> + * @registered:	Flag that specifies if this is already registered
> + */
> +struct kmsg_dumper {
> +	void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
> +			const char *s1, unsigned long l1,
> +			const char *s2, unsigned long l2);
> +	struct list_head list;
> +	int registered;
> +};
> +
> +void kmsg_dump(enum kmsg_dump_reason reason);
> +
> +int kmsg_dump_register(struct kmsg_dumper *dumper);
> +
> +int kmsg_dump_unregister(struct kmsg_dumper *dumper);
> +
> +#endif /* _LINUX_DUMP_DEVICE_H */

If you still make a new version of the patch, please correct the
"_LINUX_DUMP_DEVICE_H" comment.

A.

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v10 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-16 11:25                   ` Aaro Koskinen
  0 siblings, 0 replies; 94+ messages in thread
From: Aaro Koskinen @ 2009-10-16 11:25 UTC (permalink / raw)
  To: ext Simon Kagstrom
  Cc: dedekind1, David Woodhouse, LKML, linux-mtd, Ingo Molnar,
	Linus Torvalds, Andrew Morton, Alan Cox

Hello,

Simon Kagstrom wrote:
> +#ifndef _LINUX_KMSG_DUMP_H
> +#define _LINUX_KMSG_DUMP_H
> +
> +#include <linux/list.h>
> +
> +enum kmsg_dump_reason {
> +	KMSG_DUMP_OOPS,
> +	KMSG_DUMP_PANIC,
> +};
> +
> +/**
> + * struct kmsg_dumper - kernel crash message dumper structure
> + * @dump:	The callback which gets called on crashes. The buffer is passed
> + * 		as two sections, where s1 (length l1) contains the older
> + * 		messages and s2 (length l2) contains the newer.
> + * @list:	Entry in the dumper list (private)
> + * @registered:	Flag that specifies if this is already registered
> + */
> +struct kmsg_dumper {
> +	void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
> +			const char *s1, unsigned long l1,
> +			const char *s2, unsigned long l2);
> +	struct list_head list;
> +	int registered;
> +};
> +
> +void kmsg_dump(enum kmsg_dump_reason reason);
> +
> +int kmsg_dump_register(struct kmsg_dumper *dumper);
> +
> +int kmsg_dump_unregister(struct kmsg_dumper *dumper);
> +
> +#endif /* _LINUX_DUMP_DEVICE_H */

If you still make a new version of the patch, please correct the
"_LINUX_DUMP_DEVICE_H" comment.

A.

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-16 10:10                   ` Ingo Molnar
@ 2009-10-16 12:09                     ` Simon Kagstrom
  -1 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-16 12:09 UTC (permalink / raw)
  To: Ingo Molnar, linux-mtd
  Cc: dedekind1, Linus Torvalds, David Woodhouse, Andrew Morton, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

The core functionality is implemented as per Linus suggestion from

  http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html

(with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
been added which contains a callback to dump the kernel log buffers on
crashes. The kmsg_dump function gets called from oops_exit() and panic()
and invokes this callbacks with the crash reason.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
Reviewed-by: Ingo Molnar <mingo@elte.hu>
---
The bikeshed paint is drying:

ChangeLog:
	* (Ingo Molnar): Flatten lock use
	* (Artem, Aaro): Fix style issues

 include/linux/kmsg_dump.h |   44 ++++++++++++++++++
 kernel/panic.c            |    3 +
 kernel/printk.c           |  112 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 159 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/kmsg_dump.h

diff --git a/include/linux/kmsg_dump.h b/include/linux/kmsg_dump.h
new file mode 100644
index 0000000..7f089ec
--- /dev/null
+++ b/include/linux/kmsg_dump.h
@@ -0,0 +1,44 @@
+/*
+ * linux/include/kmsg_dump.h
+ *
+ * Copyright (C) 2009 Net Insight AB
+ *
+ * Author: Simon Kagstrom <simon.kagstrom@netinsight.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+#ifndef _LINUX_KMSG_DUMP_H
+#define _LINUX_KMSG_DUMP_H
+
+#include <linux/list.h>
+
+enum kmsg_dump_reason {
+	KMSG_DUMP_OOPS,
+	KMSG_DUMP_PANIC,
+};
+
+/**
+ * struct kmsg_dumper - kernel crash message dumper structure
+ * @dump:	The callback which gets called on crashes. The buffer is passed
+ * 		as two sections, where s1 (length l1) contains the older
+ * 		messages and s2 (length l2) contains the newer.
+ * @list:	Entry in the dumper list (private)
+ * @registered:	Flag that specifies if this is already registered
+ */
+struct kmsg_dumper {
+	void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
+			const char *s1, unsigned long l1,
+			const char *s2, unsigned long l2);
+	struct list_head list;
+	int registered;
+};
+
+void kmsg_dump(enum kmsg_dump_reason reason);
+
+int kmsg_dump_register(struct kmsg_dumper *dumper);
+
+int kmsg_dump_unregister(struct kmsg_dumper *dumper);
+
+#endif /* _LINUX_KMSG_DUMP_H */
diff --git a/kernel/panic.c b/kernel/panic.c
index c0b33b8..763296d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -10,6 +10,7 @@
  */
 #include <linux/debug_locks.h>
 #include <linux/interrupt.h>
+#include <linux/kmsg_dump.h>
 #include <linux/kallsyms.h>
 #include <linux/notifier.h>
 #include <linux/module.h>
@@ -76,6 +77,7 @@ NORET_TYPE void panic(const char * fmt, ...)
 	dump_stack();
 #endif
 
+	kmsg_dump(KMSG_DUMP_PANIC);
 	/*
 	 * If we have crashed and we have a crash kernel loaded let it handle
 	 * everything else.
@@ -341,6 +343,7 @@ void oops_exit(void)
 {
 	do_oops_enter_exit();
 	print_oops_end_marker();
+	kmsg_dump(KMSG_DUMP_OOPS);
 }
 
 #ifdef WANT_WARN_ON_SLOWPATH
diff --git a/kernel/printk.c b/kernel/printk.c
index f38b07f..f711b99 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -33,6 +33,7 @@
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
+#include <linux/kmsg_dump.h>
 
 #include <asm/uaccess.h>
 
@@ -1405,3 +1406,114 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 }
 EXPORT_SYMBOL(printk_timed_ratelimit);
 #endif
+
+static DEFINE_SPINLOCK(dump_list_lock);
+static LIST_HEAD(dump_list);
+
+/**
+ * kmsg_dump_register - register a kernel log dumper.
+ * @dump: pointer to the kmsg_dumper structure
+ *
+ * Adds a kernel log dumper to the system. The dump callback in the
+ * structure will be called when the kernel oopses or panics and must be
+ * set. Returns zero on success and %-EINVAL or %-EBUSY otherwise.
+ */
+int kmsg_dump_register(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+	int err = -EBUSY;
+
+	/* The dump callback needs to be set */
+	if (!dumper->dump)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	/* Don't allow registering multiple times */
+	if (!dumper->registered) {
+		dumper->registered = 1;
+		list_add_tail(&dumper->list, &dump_list);
+		err = 0;
+	}
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(kmsg_dump_register);
+
+/**
+ * kmsg_dump_unregister - unregister a kmsg dumper.
+ * @dump: pointer to the kmsg_dumper structure
+ *
+ * Removes a dump device from the system. Returns zero on success and
+ * %-EINVAL otherwise.
+ */
+int kmsg_dump_unregister(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+	int err = -EINVAL;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	if (dumper->registered) {
+		dumper->registered = 0;
+		list_del(&dumper->list);
+		err = 0;
+	}
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
+
+static const char const *kmsg_reasons[] = {
+	[KMSG_DUMP_OOPS]	= "oops",
+	[KMSG_DUMP_PANIC]	= "panic",
+};
+
+static const char *kmsg_to_str(enum kmsg_dump_reason reason)
+{
+	if (reason >= ARRAY_SIZE(kmsg_reasons) || reason < 0)
+		return "unknown";
+
+	return kmsg_reasons[reason];
+}
+
+/**
+ * kmsg_dump - dump kernel log to kernel message dumpers.
+ * @reason: the reason (oops, panic etc) for dumping
+ *
+ * Iterate through each of the dump devices and call the oops/panic
+ * callbacks with the log buffer.
+ */
+void kmsg_dump(enum kmsg_dump_reason reason)
+{
+	unsigned long len = ACCESS_ONCE(log_end);
+	struct kmsg_dumper *dumper;
+	const char *s1, *s2;
+	unsigned long l1, l2;
+	unsigned long flags;
+
+	s1 = "";
+	l1 = 0;
+	s2 = log_buf;
+	l2 = len;
+
+	/* Have we rotated around the circular buffer? */
+	if (len > log_buf_len) {
+		unsigned long pos = len & LOG_BUF_MASK;
+
+		s1 = log_buf + pos;
+		l1 = log_buf_len - pos;
+
+		s2 = log_buf;
+		l2 = pos;
+	}
+
+	if (!spin_trylock_irqsave(&dump_list_lock, flags)) {
+		printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n",
+				kmsg_to_str(reason));
+		return;
+	}
+	list_for_each_entry(dumper, &dump_list, list)
+		dumper->dump(dumper, reason, s1, l1, s2, l2);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+}
-- 
1.6.0.4


^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-16 12:09                     ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-16 12:09 UTC (permalink / raw)
  To: Ingo Molnar, linux-mtd
  Cc: dedekind1, Linus Torvalds, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Andrew Morton, David Woodhouse, Alan Cox

The core functionality is implemented as per Linus suggestion from

  http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html

(with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
been added which contains a callback to dump the kernel log buffers on
crashes. The kmsg_dump function gets called from oops_exit() and panic()
and invokes this callbacks with the crash reason.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
Reviewed-by: Ingo Molnar <mingo@elte.hu>
---
The bikeshed paint is drying:

ChangeLog:
	* (Ingo Molnar): Flatten lock use
	* (Artem, Aaro): Fix style issues

 include/linux/kmsg_dump.h |   44 ++++++++++++++++++
 kernel/panic.c            |    3 +
 kernel/printk.c           |  112 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 159 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/kmsg_dump.h

diff --git a/include/linux/kmsg_dump.h b/include/linux/kmsg_dump.h
new file mode 100644
index 0000000..7f089ec
--- /dev/null
+++ b/include/linux/kmsg_dump.h
@@ -0,0 +1,44 @@
+/*
+ * linux/include/kmsg_dump.h
+ *
+ * Copyright (C) 2009 Net Insight AB
+ *
+ * Author: Simon Kagstrom <simon.kagstrom@netinsight.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+#ifndef _LINUX_KMSG_DUMP_H
+#define _LINUX_KMSG_DUMP_H
+
+#include <linux/list.h>
+
+enum kmsg_dump_reason {
+	KMSG_DUMP_OOPS,
+	KMSG_DUMP_PANIC,
+};
+
+/**
+ * struct kmsg_dumper - kernel crash message dumper structure
+ * @dump:	The callback which gets called on crashes. The buffer is passed
+ * 		as two sections, where s1 (length l1) contains the older
+ * 		messages and s2 (length l2) contains the newer.
+ * @list:	Entry in the dumper list (private)
+ * @registered:	Flag that specifies if this is already registered
+ */
+struct kmsg_dumper {
+	void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
+			const char *s1, unsigned long l1,
+			const char *s2, unsigned long l2);
+	struct list_head list;
+	int registered;
+};
+
+void kmsg_dump(enum kmsg_dump_reason reason);
+
+int kmsg_dump_register(struct kmsg_dumper *dumper);
+
+int kmsg_dump_unregister(struct kmsg_dumper *dumper);
+
+#endif /* _LINUX_KMSG_DUMP_H */
diff --git a/kernel/panic.c b/kernel/panic.c
index c0b33b8..763296d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -10,6 +10,7 @@
  */
 #include <linux/debug_locks.h>
 #include <linux/interrupt.h>
+#include <linux/kmsg_dump.h>
 #include <linux/kallsyms.h>
 #include <linux/notifier.h>
 #include <linux/module.h>
@@ -76,6 +77,7 @@ NORET_TYPE void panic(const char * fmt, ...)
 	dump_stack();
 #endif
 
+	kmsg_dump(KMSG_DUMP_PANIC);
 	/*
 	 * If we have crashed and we have a crash kernel loaded let it handle
 	 * everything else.
@@ -341,6 +343,7 @@ void oops_exit(void)
 {
 	do_oops_enter_exit();
 	print_oops_end_marker();
+	kmsg_dump(KMSG_DUMP_OOPS);
 }
 
 #ifdef WANT_WARN_ON_SLOWPATH
diff --git a/kernel/printk.c b/kernel/printk.c
index f38b07f..f711b99 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -33,6 +33,7 @@
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
+#include <linux/kmsg_dump.h>
 
 #include <asm/uaccess.h>
 
@@ -1405,3 +1406,114 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 }
 EXPORT_SYMBOL(printk_timed_ratelimit);
 #endif
+
+static DEFINE_SPINLOCK(dump_list_lock);
+static LIST_HEAD(dump_list);
+
+/**
+ * kmsg_dump_register - register a kernel log dumper.
+ * @dump: pointer to the kmsg_dumper structure
+ *
+ * Adds a kernel log dumper to the system. The dump callback in the
+ * structure will be called when the kernel oopses or panics and must be
+ * set. Returns zero on success and %-EINVAL or %-EBUSY otherwise.
+ */
+int kmsg_dump_register(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+	int err = -EBUSY;
+
+	/* The dump callback needs to be set */
+	if (!dumper->dump)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	/* Don't allow registering multiple times */
+	if (!dumper->registered) {
+		dumper->registered = 1;
+		list_add_tail(&dumper->list, &dump_list);
+		err = 0;
+	}
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(kmsg_dump_register);
+
+/**
+ * kmsg_dump_unregister - unregister a kmsg dumper.
+ * @dump: pointer to the kmsg_dumper structure
+ *
+ * Removes a dump device from the system. Returns zero on success and
+ * %-EINVAL otherwise.
+ */
+int kmsg_dump_unregister(struct kmsg_dumper *dumper)
+{
+	unsigned long flags;
+	int err = -EINVAL;
+
+	spin_lock_irqsave(&dump_list_lock, flags);
+	if (dumper->registered) {
+		dumper->registered = 0;
+		list_del(&dumper->list);
+		err = 0;
+	}
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
+
+static const char const *kmsg_reasons[] = {
+	[KMSG_DUMP_OOPS]	= "oops",
+	[KMSG_DUMP_PANIC]	= "panic",
+};
+
+static const char *kmsg_to_str(enum kmsg_dump_reason reason)
+{
+	if (reason >= ARRAY_SIZE(kmsg_reasons) || reason < 0)
+		return "unknown";
+
+	return kmsg_reasons[reason];
+}
+
+/**
+ * kmsg_dump - dump kernel log to kernel message dumpers.
+ * @reason: the reason (oops, panic etc) for dumping
+ *
+ * Iterate through each of the dump devices and call the oops/panic
+ * callbacks with the log buffer.
+ */
+void kmsg_dump(enum kmsg_dump_reason reason)
+{
+	unsigned long len = ACCESS_ONCE(log_end);
+	struct kmsg_dumper *dumper;
+	const char *s1, *s2;
+	unsigned long l1, l2;
+	unsigned long flags;
+
+	s1 = "";
+	l1 = 0;
+	s2 = log_buf;
+	l2 = len;
+
+	/* Have we rotated around the circular buffer? */
+	if (len > log_buf_len) {
+		unsigned long pos = len & LOG_BUF_MASK;
+
+		s1 = log_buf + pos;
+		l1 = log_buf_len - pos;
+
+		s2 = log_buf;
+		l2 = pos;
+	}
+
+	if (!spin_trylock_irqsave(&dump_list_lock, flags)) {
+		printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n",
+				kmsg_to_str(reason));
+		return;
+	}
+	list_for_each_entry(dumper, &dump_list, list)
+		dumper->dump(dumper, reason, s1, l1, s2, l2);
+	spin_unlock_irqrestore(&dump_list_lock, flags);
+}
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* Re: [PATCH v10 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-16 11:00                     ` Artem Bityutskiy
@ 2009-10-16 12:57                       ` Ingo Molnar
  -1 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-16 12:57 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Simon Kagstrom, linux-mtd, Linus Torvalds, David Woodhouse,
	Andrew Morton, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox


* Artem Bityutskiy <dedekind1@gmail.com> wrote:

> On Fri, 2009-10-16 at 12:10 +0200, Ingo Molnar wrote:
> > * Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:
> > 
> > > +int kmsg_dump_register(struct kmsg_dumper *dumper)
> > > +{
> > > +	unsigned long flags;
> > > +
> > > +	/* The dump callback needs to be set */
> > > +	if (!dumper->dump)
> > > +		return -EINVAL;
> > > +
> > > +	spin_lock_irqsave(&dump_list_lock, flags);
> > > +
> > > +	/* Don't allow registering multiple times */
> > > +	if (dumper->registered) {
> > > +		spin_unlock_irqrestore(&dump_list_lock, flags);
> > > +
> > > +		return -EBUSY;
> > > +	}
> > > +
> > > +	dumper->registered = 1;
> > > +	list_add(&dumper->list, &dump_list);
> > > +	spin_unlock_irqrestore(&dump_list_lock, flags);
> > > +
> > > +	return 0;
> > > +}
> > > +EXPORT_SYMBOL_GPL(kmsg_dump_register);
> > 
> > 
> > i dont want to bikeshed paint this but this sequence caught my eyes. We 
> > generally do flatter and clearer locking sequences:
> > 
> > int kmsg_dump_register(struct kmsg_dumper *dumper)
> > {
> > 	unsigned long flags;
> > 	int err = -EBUSY;
> > 
> > 	/* The dump callback needs to be set */
> > 	if (!dumper->dump)
> > 		return -EINVAL;
> > 
> > 	spin_lock_irqsave(&dump_list_lock, flags);
> > 
> > 	/* Don't allow registering multiple times */
> > 	if (!dumper->registered) {
> > 		dumper->registered = 1;
> > 		list_add_tail(&dumper->list, &dump_list);
> > 		err = 0;
> > 	}
> > 
> > 	spin_unlock_irqrestore(&dump_list_lock, flags);
> > 
> > 	return err;
> > }
> > EXPORT_SYMBOL_GPL(kmsg_dump_register);
> 
> And while we are on it, I think these extra lines before and after 
> spinlocks are unneeded and even a bit annoying :-)

To me they increase readability quite a bit as it allows me to 
concentrate on just the inner critical section without the distraction 
of the lock/unlock sequence. YMMV.

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v10 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-16 12:57                       ` Ingo Molnar
  0 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-16 12:57 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: David Woodhouse, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Simon Kagstrom, Andrew Morton, Linus Torvalds,
	Alan Cox


* Artem Bityutskiy <dedekind1@gmail.com> wrote:

> On Fri, 2009-10-16 at 12:10 +0200, Ingo Molnar wrote:
> > * Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:
> > 
> > > +int kmsg_dump_register(struct kmsg_dumper *dumper)
> > > +{
> > > +	unsigned long flags;
> > > +
> > > +	/* The dump callback needs to be set */
> > > +	if (!dumper->dump)
> > > +		return -EINVAL;
> > > +
> > > +	spin_lock_irqsave(&dump_list_lock, flags);
> > > +
> > > +	/* Don't allow registering multiple times */
> > > +	if (dumper->registered) {
> > > +		spin_unlock_irqrestore(&dump_list_lock, flags);
> > > +
> > > +		return -EBUSY;
> > > +	}
> > > +
> > > +	dumper->registered = 1;
> > > +	list_add(&dumper->list, &dump_list);
> > > +	spin_unlock_irqrestore(&dump_list_lock, flags);
> > > +
> > > +	return 0;
> > > +}
> > > +EXPORT_SYMBOL_GPL(kmsg_dump_register);
> > 
> > 
> > i dont want to bikeshed paint this but this sequence caught my eyes. We 
> > generally do flatter and clearer locking sequences:
> > 
> > int kmsg_dump_register(struct kmsg_dumper *dumper)
> > {
> > 	unsigned long flags;
> > 	int err = -EBUSY;
> > 
> > 	/* The dump callback needs to be set */
> > 	if (!dumper->dump)
> > 		return -EINVAL;
> > 
> > 	spin_lock_irqsave(&dump_list_lock, flags);
> > 
> > 	/* Don't allow registering multiple times */
> > 	if (!dumper->registered) {
> > 		dumper->registered = 1;
> > 		list_add_tail(&dumper->list, &dump_list);
> > 		err = 0;
> > 	}
> > 
> > 	spin_unlock_irqrestore(&dump_list_lock, flags);
> > 
> > 	return err;
> > }
> > EXPORT_SYMBOL_GPL(kmsg_dump_register);
> 
> And while we are on it, I think these extra lines before and after 
> spinlocks are unneeded and even a bit annoying :-)

To me they increase readability quite a bit as it allows me to 
concentrate on just the inner critical section without the distraction 
of the lock/unlock sequence. YMMV.

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-16 12:09                     ` Simon Kagstrom
@ 2009-10-19 11:48                       ` Artem Bityutskiy
  -1 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-19 11:48 UTC (permalink / raw)
  To: Simon Kagstrom
  Cc: Ingo Molnar, linux-mtd, Linus Torvalds, David Woodhouse,
	Andrew Morton, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

On Fri, 2009-10-16 at 14:09 +0200, Simon Kagstrom wrote:
> The core functionality is implemented as per Linus suggestion from
> 
>   http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html
> 
> (with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
> been added which contains a callback to dump the kernel log buffers on
> crashes. The kmsg_dump function gets called from oops_exit() and panic()
> and invokes this callbacks with the crash reason.
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
> Reviewed-by: Ingo Molnar <mingo@elte.hu>
> ---
> The bikeshed paint is drying:
> 
> ChangeLog:
> 	* (Ingo Molnar): Flatten lock use
> 	* (Artem, Aaro): Fix style issues
> 
>  include/linux/kmsg_dump.h |   44 ++++++++++++++++++
>  kernel/panic.c            |    3 +
>  kernel/printk.c           |  112 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 159 insertions(+), 0 deletions(-)
>  create mode 100644 include/linux/kmsg_dump.h

I wonder, via which tree this should go in. We are going to have mtdoops
depend on this. Should we go one of these ways:

   * this patch goes to one of Ingo's tip trees, so we can pull it and
     work on top.
   * we have Ingo's / Linus' acks, and this goes via the MTD tree.
?

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-19 11:48                       ` Artem Bityutskiy
  0 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-19 11:48 UTC (permalink / raw)
  To: Simon Kagstrom
  Cc: David Woodhouse, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Ingo Molnar, Linus Torvalds, Andrew Morton, Alan Cox

On Fri, 2009-10-16 at 14:09 +0200, Simon Kagstrom wrote:
> The core functionality is implemented as per Linus suggestion from
> 
>   http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html
> 
> (with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
> been added which contains a callback to dump the kernel log buffers on
> crashes. The kmsg_dump function gets called from oops_exit() and panic()
> and invokes this callbacks with the crash reason.
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
> Reviewed-by: Ingo Molnar <mingo@elte.hu>
> ---
> The bikeshed paint is drying:
> 
> ChangeLog:
> 	* (Ingo Molnar): Flatten lock use
> 	* (Artem, Aaro): Fix style issues
> 
>  include/linux/kmsg_dump.h |   44 ++++++++++++++++++
>  kernel/panic.c            |    3 +
>  kernel/printk.c           |  112 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 159 insertions(+), 0 deletions(-)
>  create mode 100644 include/linux/kmsg_dump.h

I wonder, via which tree this should go in. We are going to have mtdoops
depend on this. Should we go one of these ways:

   * this patch goes to one of Ingo's tip trees, so we can pull it and
     work on top.
   * we have Ingo's / Linus' acks, and this goes via the MTD tree.
?

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-19 11:48                       ` Artem Bityutskiy
@ 2009-10-19 12:50                         ` Ingo Molnar
  -1 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-19 12:50 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Simon Kagstrom, linux-mtd, Linus Torvalds, David Woodhouse,
	Andrew Morton, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox


* Artem Bityutskiy <dedekind1@gmail.com> wrote:

> On Fri, 2009-10-16 at 14:09 +0200, Simon Kagstrom wrote:
> > The core functionality is implemented as per Linus suggestion from
> > 
> >   http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html
> > 
> > (with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
> > been added which contains a callback to dump the kernel log buffers on
> > crashes. The kmsg_dump function gets called from oops_exit() and panic()
> > and invokes this callbacks with the crash reason.
> > 
> > Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> > Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
> > Reviewed-by: Ingo Molnar <mingo@elte.hu>
> > ---
> > The bikeshed paint is drying:
> > 
> > ChangeLog:
> > 	* (Ingo Molnar): Flatten lock use
> > 	* (Artem, Aaro): Fix style issues
> > 
> >  include/linux/kmsg_dump.h |   44 ++++++++++++++++++
> >  kernel/panic.c            |    3 +
> >  kernel/printk.c           |  112 +++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 159 insertions(+), 0 deletions(-)
> >  create mode 100644 include/linux/kmsg_dump.h
> 
> I wonder, via which tree this should go in. We are going to have mtdoops
> depend on this. Should we go one of these ways:
> 
>    * this patch goes to one of Ingo's tip trees, so we can pull it and
>      work on top.
>    * we have Ingo's / Linus' acks, and this goes via the MTD tree.
> ?

Either way is good to me. Linus, do you have any preferences?

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-19 12:50                         ` Ingo Molnar
  0 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-19 12:50 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: David Woodhouse, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Simon Kagstrom, Andrew Morton, Linus Torvalds,
	Alan Cox


* Artem Bityutskiy <dedekind1@gmail.com> wrote:

> On Fri, 2009-10-16 at 14:09 +0200, Simon Kagstrom wrote:
> > The core functionality is implemented as per Linus suggestion from
> > 
> >   http://lists.infradead.org/pipermail/linux-mtd/2009-October/027620.html
> > 
> > (with the kmsg_dump implementation by Linus). A struct kmsg_dumper has
> > been added which contains a callback to dump the kernel log buffers on
> > crashes. The kmsg_dump function gets called from oops_exit() and panic()
> > and invokes this callbacks with the crash reason.
> > 
> > Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> > Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
> > Reviewed-by: Ingo Molnar <mingo@elte.hu>
> > ---
> > The bikeshed paint is drying:
> > 
> > ChangeLog:
> > 	* (Ingo Molnar): Flatten lock use
> > 	* (Artem, Aaro): Fix style issues
> > 
> >  include/linux/kmsg_dump.h |   44 ++++++++++++++++++
> >  kernel/panic.c            |    3 +
> >  kernel/printk.c           |  112 +++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 159 insertions(+), 0 deletions(-)
> >  create mode 100644 include/linux/kmsg_dump.h
> 
> I wonder, via which tree this should go in. We are going to have mtdoops
> depend on this. Should we go one of these ways:
> 
>    * this patch goes to one of Ingo's tip trees, so we can pull it and
>      work on top.
>    * we have Ingo's / Linus' acks, and this goes via the MTD tree.
> ?

Either way is good to me. Linus, do you have any preferences?

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-19 12:50                         ` Ingo Molnar
@ 2009-10-21 23:33                           ` Linus Torvalds
  -1 siblings, 0 replies; 94+ messages in thread
From: Linus Torvalds @ 2009-10-21 23:33 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Artem Bityutskiy, Simon Kagstrom, linux-mtd, David Woodhouse,
	Andrew Morton, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox



On Mon, 19 Oct 2009, Ingo Molnar wrote:
> > 
> > I wonder, via which tree this should go in. We are going to have mtdoops
> > depend on this. Should we go one of these ways:
> > 
> >    * this patch goes to one of Ingo's tip trees, so we can pull it and
> >      work on top.
> >    * we have Ingo's / Linus' acks, and this goes via the MTD tree.
> > ?
> 
> Either way is good to me. Linus, do you have any preferences?

Either works for me.

		Linus

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-21 23:33                           ` Linus Torvalds
  0 siblings, 0 replies; 94+ messages in thread
From: Linus Torvalds @ 2009-10-21 23:33 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Artem Bityutskiy, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Simon Kagstrom, Andrew Morton, David Woodhouse,
	Alan Cox



On Mon, 19 Oct 2009, Ingo Molnar wrote:
> > 
> > I wonder, via which tree this should go in. We are going to have mtdoops
> > depend on this. Should we go one of these ways:
> > 
> >    * this patch goes to one of Ingo's tip trees, so we can pull it and
> >      work on top.
> >    * we have Ingo's / Linus' acks, and this goes via the MTD tree.
> > ?
> 
> Either way is good to me. Linus, do you have any preferences?

Either works for me.

		Linus

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-21 23:33                           ` Linus Torvalds
@ 2009-10-22  6:25                             ` Simon Kagstrom
  -1 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-22  6:25 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Ingo Molnar, Artem Bityutskiy, linux-mtd, David Woodhouse,
	Andrew Morton, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

On Thu, 22 Oct 2009 08:33:11 +0900 (JST)
Linus Torvalds <torvalds@linux-foundation.org> wrote:

> > > I wonder, via which tree this should go in. We are going to have mtdoops
> > > depend on this. Should we go one of these ways:
> > > 
> > >    * this patch goes to one of Ingo's tip trees, so we can pull it and
> > >      work on top.
> > >    * we have Ingo's / Linus' acks, and this goes via the MTD tree.
> > > ?
> > 
> > Either way is good to me. Linus, do you have any preferences?
> 
> Either works for me.

I would put it all through Artems MTD tree then so that we keep the new
API and the user of it close together then.

Thanks to everyone for the reviewing and suggestions!

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-22  6:25                             ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-22  6:25 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Artem Bityutskiy, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Ingo Molnar, David Woodhouse, Andrew Morton, Alan Cox

On Thu, 22 Oct 2009 08:33:11 +0900 (JST)
Linus Torvalds <torvalds@linux-foundation.org> wrote:

> > > I wonder, via which tree this should go in. We are going to have mtdoops
> > > depend on this. Should we go one of these ways:
> > > 
> > >    * this patch goes to one of Ingo's tip trees, so we can pull it and
> > >      work on top.
> > >    * we have Ingo's / Linus' acks, and this goes via the MTD tree.
> > > ?
> > 
> > Either way is good to me. Linus, do you have any preferences?
> 
> Either works for me.

I would put it all through Artems MTD tree then so that we keep the new
API and the user of it close together then.

Thanks to everyone for the reviewing and suggestions!

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-22  6:25                             ` Simon Kagstrom
@ 2009-10-22  6:36                               ` Artem Bityutskiy
  -1 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-22  6:36 UTC (permalink / raw)
  To: Simon Kagstrom, David Woodhouse
  Cc: Linus Torvalds, Ingo Molnar, linux-mtd, Andrew Morton, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

On Thu, 2009-10-22 at 08:25 +0200, Simon Kagstrom wrote:
> On Thu, 22 Oct 2009 08:33:11 +0900 (JST)
> Linus Torvalds <torvalds@linux-foundation.org> wrote:
> 
> > > > I wonder, via which tree this should go in. We are going to have mtdoops
> > > > depend on this. Should we go one of these ways:
> > > > 
> > > >    * this patch goes to one of Ingo's tip trees, so we can pull it and
> > > >      work on top.
> > > >    * we have Ingo's / Linus' acks, and this goes via the MTD tree.
> > > > ?
> > > 
> > > Either way is good to me. Linus, do you have any preferences?
> > 
> > Either works for me.
> 
> I would put it all through Artems MTD tree then so that we keep the new
> API and the user of it close together then.
> 
> Thanks to everyone for the reviewing and suggestions!
> 

It's dwmw2's tree actually. I just act as his secretary :-)

David, could you push this patch to your tree? Ingo's and Linus' acks
are there, AFAIU.

Simon, I'll look at your other mtdoops patches as well a bit later.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-22  6:36                               ` Artem Bityutskiy
  0 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-22  6:36 UTC (permalink / raw)
  To: Simon Kagstrom, David Woodhouse
  Cc: LKML, Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Ingo Molnar, Linus Torvalds, Andrew Morton, Alan Cox

On Thu, 2009-10-22 at 08:25 +0200, Simon Kagstrom wrote:
> On Thu, 22 Oct 2009 08:33:11 +0900 (JST)
> Linus Torvalds <torvalds@linux-foundation.org> wrote:
> 
> > > > I wonder, via which tree this should go in. We are going to have mtdoops
> > > > depend on this. Should we go one of these ways:
> > > > 
> > > >    * this patch goes to one of Ingo's tip trees, so we can pull it and
> > > >      work on top.
> > > >    * we have Ingo's / Linus' acks, and this goes via the MTD tree.
> > > > ?
> > > 
> > > Either way is good to me. Linus, do you have any preferences?
> > 
> > Either works for me.
> 
> I would put it all through Artems MTD tree then so that we keep the new
> API and the user of it close together then.
> 
> Thanks to everyone for the reviewing and suggestions!
> 

It's dwmw2's tree actually. I just act as his secretary :-)

David, could you push this patch to your tree? Ingo's and Linus' acks
are there, AFAIU.

Simon, I'll look at your other mtdoops patches as well a bit later.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-22  6:36                               ` Artem Bityutskiy
  (?)
@ 2009-10-22  6:42                               ` Simon Kagstrom
  2009-10-22  8:52                                 ` Artem Bityutskiy
  -1 siblings, 1 reply; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-22  6:42 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd, David Woodhouse, Koskinen Aaro (Nokia-D/Helsinki)

(Removing some people from Cc:)

On Thu, 22 Oct 2009 09:36:08 +0300
Artem Bityutskiy <dedekind1@gmail.com> wrote:
> > I would put it all through Artems MTD tree then so that we keep the new
> > API and the user of it close together then.
> 
> It's dwmw2's tree actually. I just act as his secretary :-)
> 
> David, could you push this patch to your tree? Ingo's and Linus' acks
> are there, AFAIU.

I know it's Davids tree :-)

I just thought it would be a good idea to keep everything together
through your tree first before asking David to merge it.


But it's better to take in only the core patch first as you suggest.

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-22  6:42                               ` Simon Kagstrom
@ 2009-10-22  8:52                                 ` Artem Bityutskiy
  2009-10-22  8:58                                   ` Simon Kagstrom
  0 siblings, 1 reply; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-22  8:52 UTC (permalink / raw)
  To: Simon Kagstrom
  Cc: linux-mtd, David Woodhouse, Koskinen Aaro (Nokia-D/Helsinki)

On Thu, 2009-10-22 at 08:42 +0200, Simon Kagstrom wrote:
> (Removing some people from Cc:)
> 
> On Thu, 22 Oct 2009 09:36:08 +0300
> Artem Bityutskiy <dedekind1@gmail.com> wrote:
> > > I would put it all through Artems MTD tree then so that we keep the new
> > > API and the user of it close together then.
> > 
> > It's dwmw2's tree actually. I just act as his secretary :-)
> > 
> > David, could you push this patch to your tree? Ingo's and Linus' acks
> > are there, AFAIU.
> 
> I know it's Davids tree :-)
> 
> I just thought it would be a good idea to keep everything together
> through your tree first before asking David to merge it.
> 
> 
> But it's better to take in only the core patch first as you suggest.

Well, let's wait for what dwmw2 does. But for now I just put this patch
to my l2 tree.

FYI, I never meant to have this tree for developers, so I always rebased
it. Can you leave with this? Or you want me to create a branch which I
won't re-base?

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-22  8:52                                 ` Artem Bityutskiy
@ 2009-10-22  8:58                                   ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-22  8:58 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd, David Woodhouse, Koskinen Aaro (Nokia-D/Helsinki)

On Thu, 22 Oct 2009 11:52:56 +0300
Artem Bityutskiy <dedekind1@gmail.com> wrote:

> Well, let's wait for what dwmw2 does. But for now I just put this patch
> to my l2 tree.
> 
> FYI, I never meant to have this tree for developers, so I always rebased
> it. Can you leave with this? Or you want me to create a branch which I
> won't re-base?

I'm fine with having it rebased.

Thanks,
// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v7 1/5]: mtdoops: avoid erasing already empty areas
  2009-10-15  7:47 ` [PATCH v7 1/5]: mtdoops: avoid erasing already empty areas Simon Kagstrom
@ 2009-10-23  3:57   ` Artem Bityutskiy
  0 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-23  3:57 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: David Woodhouse, linux-mtd

On Thu, 2009-10-15 at 09:47 +0200, Simon Kagstrom wrote:
> After having scanned the entire mtdoops area, mtdoops will erase it if
> there are no mtdoops headers in it. However, empty and already erased
> areas (i.e., without mtdoops headers) will therefore also be erased at
> each startup.
> 
> This patch counts the number of unclean pages (neither empty nor with
> the mtdoops header) and only erases if no headers are found and the area
> is still unclean.
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>

Actually, it is safer to erase the partition. This is exactly why JFFS2
has erase markers. On NOR flash, if you interrupt an erase operation
(e.g., by re-booting), you may end up with unstable bits, which are read
as '1' sometimes, but sometimes they may be read as '1'. Or you may end
up with 0xFF's at the beginning, and garbage at the end.

When you erase the partition before starting using it, you make sure you
start with eraseblocks in normal state.

In practice, we observed stuff like that only on NOR, so if this is a
performance issue for you, you can make the erasure to be mandatory only
on NOR, but this won't be very nice.

BTW, we could also add some limit to the partition size of MTD oops. If
users use mtdoops with 256MiB partition, e.g., by mistake, it does not
make sense and we may just refuse it, instead of erasing.

-----
Side note, not a request to implement, but if you add a comment to the
code about this, it may be nice
-----

BTW, this suggests that before erasing eraseblocks in MTD oops, you need
to "invalidate" them by writing, say zeroes, to the second byte of the
eraseblock, if this is NOR. This is what we added to UBI recently,
because otherwise unclean reboots made it fail horribly on NOR, If you
are interested, you may take a look at the 'nor_erase_prepare()'
function in drivers/mtd/ubi/io.c

But again, this is NOR-specific.



-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v7 2/5]: mtdoops: Keep track of used/unused mtdoops pages in an array
  2009-10-15  7:47 ` [PATCH v7 2/5]: mtdoops: Keep track of used/unused mtdoops pages in an array Simon Kagstrom
@ 2009-10-23  4:08   ` Artem Bityutskiy
  0 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-23  4:08 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: David Woodhouse, linux-mtd

On Thu, 2009-10-15 at 09:47 +0200, Simon Kagstrom wrote:
> This patch makes mtdoops keep track of used/unused pages in an array
> instead of scanning the flash after a write. The advantage with this
> approach is that it avoids calling mtd->read on a panic, which is not
> possible for all mtd drivers.
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
Reviewed-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v7 3/5]: mtdoops: Make page (record) size configurable
  2009-10-15  7:47 ` [PATCH v7 3/5]: mtdoops: Make page (record) size configurable Simon Kagstrom
@ 2009-10-23  4:13   ` Artem Bityutskiy
  2009-10-23  6:58     ` Simon Kagstrom
  0 siblings, 1 reply; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-23  4:13 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: David Woodhouse, linux-mtd

On Thu, 2009-10-15 at 09:47 +0200, Simon Kagstrom wrote:
> The main justification for this is to allow catching long messages
> during a panic, where the top part might otherwise be lost since moving
> to the next block can require a flash erase.
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>

What will happen if I have a partition with 8192-bytes records, and then
attach it to mtdoops with default 4096 ?

>  	cxt->mtd = mtd;
>  	if (mtd->size > INT_MAX)
> -		cxt->oops_pages = INT_MAX / OOPS_PAGE_SIZE;
> +		cxt->oops_pages = INT_MAX / record_size;
>  	else
> -		cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE;
> +		cxt->oops_pages = (int)mtd->size / record_size;

BTW, this INT_MAX and the (int) cast also suggests we need to limit the
maximum partition size and add a check for this.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v7 5/5]: mtdoops: refactor as a kmsg_dumper
  2009-10-15  7:48 ` [PATCH v7 5/5]: mtdoops: refactor as a kmsg_dumper Simon Kagstrom
  2009-10-15 14:10   ` [PATCH v8 " Simon Kagstrom
@ 2009-10-23  4:32   ` Artem Bityutskiy
  2009-10-23  6:34     ` Simon Kagstrom
  2010-01-06 14:33   ` David Woodhouse
  2 siblings, 1 reply; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-23  4:32 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: David Woodhouse, linux-mtd

On Thu, 2009-10-15 at 09:48 +0200, Simon Kagstrom wrote:
> The last messages which happens before a crash might contain interesting
> information about the crash. This patch reworks mtdoops using the
> kmsg_dumper support instead of a console, which simplifies the code and
> also includes the messages before the oops started.
> 
> On oops callbacks, the MTD device write is scheduled in a work queue (to
> be able to use the regular mtd->write call), while panics call
> mtd->panic_write directly. Thus, if panic_on_oops is set, the oops will
> be written out during the panic.
> 
> A parameter to specify which mtd device to use (number or name), as well
> as a flag, writable at runtime, to toggle wheter to dump oopses or only
> panics (since oopses can often be handled by regular syslog).
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
> ---
> ChangeLog:
> 	* (Vimal Singh) Correct Kconfig instructions on how to load
> 	  the module
> 	* Correct kfree of unallocated area
>         * More descriptive error message on wrong module parameters
> 	* Rebase against new patch 4 (use container_of instead of private
>           pointer)
> 
>  drivers/mtd/Kconfig   |    5 +-
>  drivers/mtd/mtdoops.c |  211 ++++++++++++++++++++-----------------------------
>  2 files changed, 88 insertions(+), 128 deletions(-)

Looks good, thanks for doing this. Did you actually test this with
oopses and panics, with and without panic_on_oops?

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v7 5/5]: mtdoops: refactor as a kmsg_dumper
  2009-10-23  4:32   ` [PATCH v7 " Artem Bityutskiy
@ 2009-10-23  6:34     ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-23  6:34 UTC (permalink / raw)
  To: dedekind1; +Cc: David Woodhouse, linux-mtd

On Fri, 23 Oct 2009 07:32:42 +0300
Artem Bityutskiy <dedekind1@gmail.com> wrote:

> On Thu, 2009-10-15 at 09:48 +0200, Simon Kagstrom wrote:
> > The last messages which happens before a crash might contain interesting
> > information about the crash. This patch reworks mtdoops using the
> > kmsg_dumper support instead of a console, which simplifies the code and
> > also includes the messages before the oops started.
> 
> Looks good, thanks for doing this. Did you actually test this with
> oopses and panics, with and without panic_on_oops?

Yes, I've tested it with the kinds of crashes I could think of on a
device (OpenRD) with a NAND flash. It works well for all cases I've
tested.

I wrote a small kernel module which registers a sysfs interface where
you can crash or cause problems for the kernel in various ways to test
this. If there is interest for it I could post it.

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v7 3/5]: mtdoops: Make page (record) size configurable
  2009-10-23  4:13   ` Artem Bityutskiy
@ 2009-10-23  6:58     ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-23  6:58 UTC (permalink / raw)
  To: dedekind1; +Cc: David Woodhouse, linux-mtd

On Fri, 23 Oct 2009 07:13:49 +0300
Artem Bityutskiy <dedekind1@gmail.com> wrote:

> On Thu, 2009-10-15 at 09:47 +0200, Simon Kagstrom wrote:
> > The main justification for this is to allow catching long messages
> > during a panic, where the top part might otherwise be lost since moving
> > to the next block can require a flash erase.
> > 
> > Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> > Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
> 
> What will happen if I have a partition with 8192-bytes records, and then
> attach it to mtdoops with default 4096 ?

Assuming you have a crash stored, it will keep the first 4KB of it and
mark the second 4KB as unclean. This will then trigger an erase where
it will first move to the next erase block above and erase that (see
mtdoops_inc_counter and mtdoops_workfunc_erase).

So until you've wrapped around to the 8KB record again, it will be
kept. Userspace code to readout the mtdoops partition would have to be
prepared for different sized blocks in this case.


In practice, I think that it's best to erase the oops area if you
decide to change the size.

> >  	cxt->mtd = mtd;
> >  	if (mtd->size > INT_MAX)
> > -		cxt->oops_pages = INT_MAX / OOPS_PAGE_SIZE;
> > +		cxt->oops_pages = INT_MAX / record_size;
> >  	else
> > -		cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE;
> > +		cxt->oops_pages = (int)mtd->size / record_size;
> 
> BTW, this INT_MAX and the (int) cast also suggests we need to limit the
> maximum partition size and add a check for this.

OK, I'll make a patch to limit this.

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-22  6:36                               ` Artem Bityutskiy
@ 2009-10-23  7:22                                 ` Ingo Molnar
  -1 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-23  7:22 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Simon Kagstrom, David Woodhouse, Linus Torvalds, linux-mtd,
	Andrew Morton, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox


* Artem Bityutskiy <dedekind1@gmail.com> wrote:

> On Thu, 2009-10-22 at 08:25 +0200, Simon Kagstrom wrote:
> > On Thu, 22 Oct 2009 08:33:11 +0900 (JST)
> > Linus Torvalds <torvalds@linux-foundation.org> wrote:
> > 
> > > > > I wonder, via which tree this should go in. We are going to have mtdoops
> > > > > depend on this. Should we go one of these ways:
> > > > > 
> > > > >    * this patch goes to one of Ingo's tip trees, so we can pull it and
> > > > >      work on top.
> > > > >    * we have Ingo's / Linus' acks, and this goes via the MTD tree.
> > > > > ?
> > > > 
> > > > Either way is good to me. Linus, do you have any preferences?
> > > 
> > > Either works for me.
> > 
> > I would put it all through Artems MTD tree then so that we keep the new
> > API and the user of it close together then.
> > 
> > Thanks to everyone for the reviewing and suggestions!
> > 
> 
> It's dwmw2's tree actually. I just act as his secretary :-)
> 
> David, could you push this patch to your tree? Ingo's and Linus' acks 
> are there, AFAIU.

Yeah, the latest bits also have my:

Acked-by: Ingo Molnar <mingo@elte.hu>

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-23  7:22                                 ` Ingo Molnar
  0 siblings, 0 replies; 94+ messages in thread
From: Ingo Molnar @ 2009-10-23  7:22 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: David Woodhouse, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Simon Kagstrom, Andrew Morton, Linus Torvalds,
	Alan Cox


* Artem Bityutskiy <dedekind1@gmail.com> wrote:

> On Thu, 2009-10-22 at 08:25 +0200, Simon Kagstrom wrote:
> > On Thu, 22 Oct 2009 08:33:11 +0900 (JST)
> > Linus Torvalds <torvalds@linux-foundation.org> wrote:
> > 
> > > > > I wonder, via which tree this should go in. We are going to have mtdoops
> > > > > depend on this. Should we go one of these ways:
> > > > > 
> > > > >    * this patch goes to one of Ingo's tip trees, so we can pull it and
> > > > >      work on top.
> > > > >    * we have Ingo's / Linus' acks, and this goes via the MTD tree.
> > > > > ?
> > > > 
> > > > Either way is good to me. Linus, do you have any preferences?
> > > 
> > > Either works for me.
> > 
> > I would put it all through Artems MTD tree then so that we keep the new
> > API and the user of it close together then.
> > 
> > Thanks to everyone for the reviewing and suggestions!
> > 
> 
> It's dwmw2's tree actually. I just act as his secretary :-)
> 
> David, could you push this patch to your tree? Ingo's and Linus' acks 
> are there, AFAIU.

Yeah, the latest bits also have my:

Acked-by: Ingo Molnar <mingo@elte.hu>

	Ingo

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-22  6:25                             ` Simon Kagstrom
@ 2009-10-23 15:53                               ` Shargorodsky Atal (EXT-Teleca/Helsinki)
  -1 siblings, 0 replies; 94+ messages in thread
From: Shargorodsky Atal (EXT-Teleca/Helsinki) @ 2009-10-23 15:53 UTC (permalink / raw)
  To: ext Simon Kagstrom
  Cc: Linus Torvalds, Ingo Molnar, Artem Bityutskiy, linux-mtd,
	David Woodhouse, Andrew Morton, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

Hi all,

On Thu, 2009-10-22 at 08:25 +0200, ext Simon Kagstrom wrote:

> Thanks to everyone for the reviewing and suggestions!
> 

I have a couple of questions:

1. If somebody writes a module that uses dumper for uploading the
oopses/panics logs via some pay-per-byte medium,  since he has no way
to know in a module if the panic_on_oops flag is set, he'll have
to upload both oops and the following panic, because he does not
know for sure that the panic was caused by the oops. Hence he
pays twice for the same information, right?

I can think of a couple of way to figure it out in the module
itself, but I could not think of any clean way to do it.


2. We tried to use panic notifiers mechanism to print additional
information that we want to see in mtdoops logs and it worked well,
but having the kmsg_dump(KMSG_DUMP_PANIC) before the
atomic_notifier_call_chain() breaks this functionality.
Can we the call kmsg_dump() after the notifiers had been invoked?


Thanks,
Atal.

> // Simon
> --
> 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/


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-23 15:53                               ` Shargorodsky Atal (EXT-Teleca/Helsinki)
  0 siblings, 0 replies; 94+ messages in thread
From: Shargorodsky Atal (EXT-Teleca/Helsinki) @ 2009-10-23 15:53 UTC (permalink / raw)
  To: ext Simon Kagstrom
  Cc: Artem Bityutskiy, David Woodhouse, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Ingo Molnar, Linus Torvalds, Andrew Morton, Alan Cox

Hi all,

On Thu, 2009-10-22 at 08:25 +0200, ext Simon Kagstrom wrote:

> Thanks to everyone for the reviewing and suggestions!
> 

I have a couple of questions:

1. If somebody writes a module that uses dumper for uploading the
oopses/panics logs via some pay-per-byte medium,  since he has no way
to know in a module if the panic_on_oops flag is set, he'll have
to upload both oops and the following panic, because he does not
know for sure that the panic was caused by the oops. Hence he
pays twice for the same information, right?

I can think of a couple of way to figure it out in the module
itself, but I could not think of any clean way to do it.


2. We tried to use panic notifiers mechanism to print additional
information that we want to see in mtdoops logs and it worked well,
but having the kmsg_dump(KMSG_DUMP_PANIC) before the
atomic_notifier_call_chain() breaks this functionality.
Can we the call kmsg_dump() after the notifiers had been invoked?


Thanks,
Atal.

> // Simon
> --
> 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/

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-23 15:53                               ` Shargorodsky Atal (EXT-Teleca/Helsinki)
@ 2009-10-24 17:05                                 ` Artem Bityutskiy
  -1 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-24 17:05 UTC (permalink / raw)
  To: Shargorodsky Atal (EXT-Teleca/Helsinki)
  Cc: Simon Kagstrom, Linus Torvalds, Ingo Molnar, linux-mtd,
	David Woodhouse, Andrew Morton, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

On Fri, 2009-10-23 at 18:53 +0300, Shargorodsky Atal
(EXT-Teleca/Helsinki) wrote:
> Hi all,
> 
> On Thu, 2009-10-22 at 08:25 +0200, ext Simon Kagstrom wrote:
> 
> > Thanks to everyone for the reviewing and suggestions!
> > 
> 
> I have a couple of questions:
> 
> 1. If somebody writes a module that uses dumper for uploading the
> oopses/panics logs via some pay-per-byte medium,  since he has no way
> to know in a module if the panic_on_oops flag is set, he'll have
> to upload both oops and the following panic, because he does not
> know for sure that the panic was caused by the oops. Hence he
> pays twice for the same information, right?

Looks like a valid point to me. Indeed, in this case we will first call
'kmsg_dump(KMSG_DUMP_OOPS)' from 'oops_exit()', and then call it from
'panic()'. And the dumper may dump the same information, which is not
nice.

I've looked briefly and tried to figure out how to fix this. But I
cannot find an clean way. And I was confused by the die/oops/etc code.
My question is, why the code does not work the following way instead?

diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 2d8a371..8f322c7 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -235,13 +235,12 @@ void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
        raw_local_irq_restore(flags);
        oops_exit();

-       if (!signr)
-               return;
        if (in_interrupt())
                panic("Fatal exception in interrupt");
        if (panic_on_oops)
                panic("Fatal exception");
-       do_exit(signr);
+       if (signr)
+               do_exit(signr);
 }

 int __kprobes __die(const char *str, struct pt_regs *regs, long err)

If the code worked like this, I think the problem indicated by Atal
could be easily fixed.

> 2. We tried to use panic notifiers mechanism to print additional
> information that we want to see in mtdoops logs and it worked well,
> but having the kmsg_dump(KMSG_DUMP_PANIC) before the
> atomic_notifier_call_chain() breaks this functionality.
> Can we the call kmsg_dump() after the notifiers had been invoked?

Atal, I think you should just attach your patch, it is easier to express
what you mean.

But for me it looks like atomic_notifier_call_chain() can be moved up.

Anyway, please, show your patch.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)


^ permalink raw reply related	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-24 17:05                                 ` Artem Bityutskiy
  0 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-24 17:05 UTC (permalink / raw)
  To: Shargorodsky Atal (EXT-Teleca/Helsinki)
  Cc: David Woodhouse, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Simon Kagstrom, Andrew Morton, Linus Torvalds,
	Ingo Molnar, Alan Cox

On Fri, 2009-10-23 at 18:53 +0300, Shargorodsky Atal
(EXT-Teleca/Helsinki) wrote:
> Hi all,
> 
> On Thu, 2009-10-22 at 08:25 +0200, ext Simon Kagstrom wrote:
> 
> > Thanks to everyone for the reviewing and suggestions!
> > 
> 
> I have a couple of questions:
> 
> 1. If somebody writes a module that uses dumper for uploading the
> oopses/panics logs via some pay-per-byte medium,  since he has no way
> to know in a module if the panic_on_oops flag is set, he'll have
> to upload both oops and the following panic, because he does not
> know for sure that the panic was caused by the oops. Hence he
> pays twice for the same information, right?

Looks like a valid point to me. Indeed, in this case we will first call
'kmsg_dump(KMSG_DUMP_OOPS)' from 'oops_exit()', and then call it from
'panic()'. And the dumper may dump the same information, which is not
nice.

I've looked briefly and tried to figure out how to fix this. But I
cannot find an clean way. And I was confused by the die/oops/etc code.
My question is, why the code does not work the following way instead?

diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 2d8a371..8f322c7 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -235,13 +235,12 @@ void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
        raw_local_irq_restore(flags);
        oops_exit();

-       if (!signr)
-               return;
        if (in_interrupt())
                panic("Fatal exception in interrupt");
        if (panic_on_oops)
                panic("Fatal exception");
-       do_exit(signr);
+       if (signr)
+               do_exit(signr);
 }

 int __kprobes __die(const char *str, struct pt_regs *regs, long err)

If the code worked like this, I think the problem indicated by Atal
could be easily fixed.

> 2. We tried to use panic notifiers mechanism to print additional
> information that we want to see in mtdoops logs and it worked well,
> but having the kmsg_dump(KMSG_DUMP_PANIC) before the
> atomic_notifier_call_chain() breaks this functionality.
> Can we the call kmsg_dump() after the notifiers had been invoked?

Atal, I think you should just attach your patch, it is easier to express
what you mean.

But for me it looks like atomic_notifier_call_chain() can be moved up.

Anyway, please, show your patch.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-23 15:53                               ` Shargorodsky Atal (EXT-Teleca/Helsinki)
@ 2009-10-26  7:41                                 ` Simon Kagstrom
  -1 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-26  7:41 UTC (permalink / raw)
  To: Shargorodsky Atal (EXT-Teleca/Helsinki)
  Cc: Linus Torvalds, Ingo Molnar, Artem Bityutskiy, linux-mtd,
	David Woodhouse, Andrew Morton, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

On Fri, 23 Oct 2009 18:53:22 +0300
"Shargorodsky Atal (EXT-Teleca/Helsinki)" <ext-atal.shargorodsky@nokia.com> wrote:

> 1. If somebody writes a module that uses dumper for uploading the
> oopses/panics logs via some pay-per-byte medium,  since he has no way
> to know in a module if the panic_on_oops flag is set, he'll have
> to upload both oops and the following panic, because he does not
> know for sure that the panic was caused by the oops. Hence he
> pays twice for the same information, right?
> 
> I can think of a couple of way to figure it out in the module
> itself, but I could not think of any clean way to do it.

This is correct, and the mtdoops driver has some provisions to handle
this. First, there is a parameter to the module to specify whether
oopses should be dumped at all - I added this for the particular case
that someone has panic_on_oops set.

Second, it does not dump oopses directly anyway, but puts it in a work
queue. That way, if panic_on_oops is set, it will store the panic but
the oops (called from the workqueue) will not get written anyway.

> 2. We tried to use panic notifiers mechanism to print additional
> information that we want to see in mtdoops logs and it worked well,
> but having the kmsg_dump(KMSG_DUMP_PANIC) before the
> atomic_notifier_call_chain() breaks this functionality.
> Can we the call kmsg_dump() after the notifiers had been invoked?

Well, it depends I think. The code currently looks like this:

	kmsg_dump(KMSG_DUMP_PANIC);
	/*
	 * If we have crashed and we have a crash kernel loaded let it handle
	 * everything else.
	 * Do we want to call this before we try to display a message?
	 */
	crash_kexec(NULL);
	[... Comments removed]
	atomic_notifier_call_chain(&panic_notifier_list, 0, buf);

And moving kdump_msg() after crash_kexec() will make us miss the
message if we have a kexec crash kernel as well. I realise that these
two approaches might be complementary and are not likely to be used at
the same time, but it's still something to think about.

Then again, maybe it's possible to move the panic notifiers above
crash_kexec() as well, which would solve things nicely.

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-26  7:41                                 ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-26  7:41 UTC (permalink / raw)
  To: Shargorodsky Atal (EXT-Teleca/Helsinki)
  Cc: Artem Bityutskiy, David Woodhouse, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Ingo Molnar, Linus Torvalds, Andrew Morton, Alan Cox

On Fri, 23 Oct 2009 18:53:22 +0300
"Shargorodsky Atal (EXT-Teleca/Helsinki)" <ext-atal.shargorodsky@nokia.com> wrote:

> 1. If somebody writes a module that uses dumper for uploading the
> oopses/panics logs via some pay-per-byte medium,  since he has no way
> to know in a module if the panic_on_oops flag is set, he'll have
> to upload both oops and the following panic, because he does not
> know for sure that the panic was caused by the oops. Hence he
> pays twice for the same information, right?
> 
> I can think of a couple of way to figure it out in the module
> itself, but I could not think of any clean way to do it.

This is correct, and the mtdoops driver has some provisions to handle
this. First, there is a parameter to the module to specify whether
oopses should be dumped at all - I added this for the particular case
that someone has panic_on_oops set.

Second, it does not dump oopses directly anyway, but puts it in a work
queue. That way, if panic_on_oops is set, it will store the panic but
the oops (called from the workqueue) will not get written anyway.

> 2. We tried to use panic notifiers mechanism to print additional
> information that we want to see in mtdoops logs and it worked well,
> but having the kmsg_dump(KMSG_DUMP_PANIC) before the
> atomic_notifier_call_chain() breaks this functionality.
> Can we the call kmsg_dump() after the notifiers had been invoked?

Well, it depends I think. The code currently looks like this:

	kmsg_dump(KMSG_DUMP_PANIC);
	/*
	 * If we have crashed and we have a crash kernel loaded let it handle
	 * everything else.
	 * Do we want to call this before we try to display a message?
	 */
	crash_kexec(NULL);
	[... Comments removed]
	atomic_notifier_call_chain(&panic_notifier_list, 0, buf);

And moving kdump_msg() after crash_kexec() will make us miss the
message if we have a kexec crash kernel as well. I realise that these
two approaches might be complementary and are not likely to be used at
the same time, but it's still something to think about.

Then again, maybe it's possible to move the panic notifiers above
crash_kexec() as well, which would solve things nicely.

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-26  7:41                                 ` Simon Kagstrom
@ 2009-10-26 10:36                                   ` Shargorodsky Atal (EXT-Teleca/Helsinki)
  -1 siblings, 0 replies; 94+ messages in thread
From: Shargorodsky Atal (EXT-Teleca/Helsinki) @ 2009-10-26 10:36 UTC (permalink / raw)
  To: ext Simon Kagstrom
  Cc: Linus Torvalds, Ingo Molnar, Artem Bityutskiy, linux-mtd,
	David Woodhouse, Andrew Morton, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

On Mon, 2009-10-26 at 08:41 +0100, ext Simon Kagstrom wrote:
> On Fri, 23 Oct 2009 18:53:22 +0300
> "Shargorodsky Atal (EXT-Teleca/Helsinki)" <ext-atal.shargorodsky@nokia.com> wrote:
> 
> > 1. If somebody writes a module that uses dumper for uploading the
> > oopses/panics logs via some pay-per-byte medium,  since he has no way
> > to know in a module if the panic_on_oops flag is set, he'll have
> > to upload both oops and the following panic, because he does not
> > know for sure that the panic was caused by the oops. Hence he
> > pays twice for the same information, right?
> > 
> > I can think of a couple of way to figure it out in the module
> > itself, but I could not think of any clean way to do it.
> 
> This is correct, and the mtdoops driver has some provisions to handle
> this. First, there is a parameter to the module to specify whether
> oopses should be dumped at all - I added this for the particular case
> that someone has panic_on_oops set.
> 

It takes care of most of the situations, but panic_on_oops
can be changed any time, even after the module is loaded.

While I think that exporting oops_on_panic is a wrong thing to do,
I believe that dumpers differ a bit from the rest of the modules in
that aspect and should be at least hinted about this flag setting.
Does it not make sense?

> Second, it does not dump oopses directly anyway, but puts it in a work
> queue. That way, if panic_on_oops is set, it will store the panic but
> the oops (called from the workqueue) will not get written anyway.
> 

AFAIK, mtdoops does not put oopses in a work queue. And if by any chance
it does, then I think it's wrong and might lead to missed oopses, as
the oops might be because of the work queues themselves, or it might
look to the kernel like some non-fatal fault, but actually it's a
sign of a much more catastrophic failure - IOMMU device garbaging
memory, for instance.

But anyway, I was not talking about mtdoops. In fact, I was not
talking about any particular module, I just described some situation
which looks a bit problematic to me.

> > 2. We tried to use panic notifiers mechanism to print additional
> > information that we want to see in mtdoops logs and it worked well,
> > but having the kmsg_dump(KMSG_DUMP_PANIC) before the
> > atomic_notifier_call_chain() breaks this functionality.
> > Can we the call kmsg_dump() after the notifiers had been invoked?
> 
> Well, it depends I think. The code currently looks like this:
> 
> 	kmsg_dump(KMSG_DUMP_PANIC);
> 	/*
> 	 * If we have crashed and we have a crash kernel loaded let it handle
> 	 * everything else.
> 	 * Do we want to call this before we try to display a message?
> 	 */
> 	crash_kexec(NULL);
> 	[... Comments removed]
> 	atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
> 
> And moving kdump_msg() after crash_kexec() will make us miss the
> message if we have a kexec crash kernel as well. I realise that these
> two approaches might be complementary and are not likely to be used at
> the same time, but it's still something to think about.
> 
> Then again, maybe it's possible to move the panic notifiers above
> crash_kexec() as well, which would solve things nicely.
> 

Which leaves me no choice but just ask the question, as it bothering me
for some time: does anybody know why we try to crash_kexec() at so early
stage?


> // Simon


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-26 10:36                                   ` Shargorodsky Atal (EXT-Teleca/Helsinki)
  0 siblings, 0 replies; 94+ messages in thread
From: Shargorodsky Atal (EXT-Teleca/Helsinki) @ 2009-10-26 10:36 UTC (permalink / raw)
  To: ext Simon Kagstrom
  Cc: Artem Bityutskiy, David Woodhouse, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Ingo Molnar, Linus Torvalds, Andrew Morton, Alan Cox

On Mon, 2009-10-26 at 08:41 +0100, ext Simon Kagstrom wrote:
> On Fri, 23 Oct 2009 18:53:22 +0300
> "Shargorodsky Atal (EXT-Teleca/Helsinki)" <ext-atal.shargorodsky@nokia.com> wrote:
> 
> > 1. If somebody writes a module that uses dumper for uploading the
> > oopses/panics logs via some pay-per-byte medium,  since he has no way
> > to know in a module if the panic_on_oops flag is set, he'll have
> > to upload both oops and the following panic, because he does not
> > know for sure that the panic was caused by the oops. Hence he
> > pays twice for the same information, right?
> > 
> > I can think of a couple of way to figure it out in the module
> > itself, but I could not think of any clean way to do it.
> 
> This is correct, and the mtdoops driver has some provisions to handle
> this. First, there is a parameter to the module to specify whether
> oopses should be dumped at all - I added this for the particular case
> that someone has panic_on_oops set.
> 

It takes care of most of the situations, but panic_on_oops
can be changed any time, even after the module is loaded.

While I think that exporting oops_on_panic is a wrong thing to do,
I believe that dumpers differ a bit from the rest of the modules in
that aspect and should be at least hinted about this flag setting.
Does it not make sense?

> Second, it does not dump oopses directly anyway, but puts it in a work
> queue. That way, if panic_on_oops is set, it will store the panic but
> the oops (called from the workqueue) will not get written anyway.
> 

AFAIK, mtdoops does not put oopses in a work queue. And if by any chance
it does, then I think it's wrong and might lead to missed oopses, as
the oops might be because of the work queues themselves, or it might
look to the kernel like some non-fatal fault, but actually it's a
sign of a much more catastrophic failure - IOMMU device garbaging
memory, for instance.

But anyway, I was not talking about mtdoops. In fact, I was not
talking about any particular module, I just described some situation
which looks a bit problematic to me.

> > 2. We tried to use panic notifiers mechanism to print additional
> > information that we want to see in mtdoops logs and it worked well,
> > but having the kmsg_dump(KMSG_DUMP_PANIC) before the
> > atomic_notifier_call_chain() breaks this functionality.
> > Can we the call kmsg_dump() after the notifiers had been invoked?
> 
> Well, it depends I think. The code currently looks like this:
> 
> 	kmsg_dump(KMSG_DUMP_PANIC);
> 	/*
> 	 * If we have crashed and we have a crash kernel loaded let it handle
> 	 * everything else.
> 	 * Do we want to call this before we try to display a message?
> 	 */
> 	crash_kexec(NULL);
> 	[... Comments removed]
> 	atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
> 
> And moving kdump_msg() after crash_kexec() will make us miss the
> message if we have a kexec crash kernel as well. I realise that these
> two approaches might be complementary and are not likely to be used at
> the same time, but it's still something to think about.
> 
> Then again, maybe it's possible to move the panic notifiers above
> crash_kexec() as well, which would solve things nicely.
> 

Which leaves me no choice but just ask the question, as it bothering me
for some time: does anybody know why we try to crash_kexec() at so early
stage?


> // Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-24 17:05                                 ` Artem Bityutskiy
@ 2009-10-26 10:40                                   ` Shargorodsky Atal (EXT-Teleca/Helsinki)
  -1 siblings, 0 replies; 94+ messages in thread
From: Shargorodsky Atal (EXT-Teleca/Helsinki) @ 2009-10-26 10:40 UTC (permalink / raw)
  To: dedekind1
  Cc: Simon Kagstrom, Linus Torvalds, Ingo Molnar, linux-mtd,
	David Woodhouse, Andrew Morton, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

On Sat, 2009-10-24 at 19:05 +0200, Artem Bityutskiy wrote:
> On Fri, 2009-10-23 at 18:53 +0300, Shargorodsky Atal
> (EXT-Teleca/Helsinki) wrote:
> > Hi all,
> > 
> > On Thu, 2009-10-22 at 08:25 +0200, ext Simon Kagstrom wrote:
> > 
> > > Thanks to everyone for the reviewing and suggestions!
> > > 
> > 
> > I have a couple of questions:
> > 
> > 1. If somebody writes a module that uses dumper for uploading the
> > oopses/panics logs via some pay-per-byte medium,  since he has no way
> > to know in a module if the panic_on_oops flag is set, he'll have
> > to upload both oops and the following panic, because he does not
> > know for sure that the panic was caused by the oops. Hence he
> > pays twice for the same information, right?
> 
> Looks like a valid point to me. Indeed, in this case we will first call
> 'kmsg_dump(KMSG_DUMP_OOPS)' from 'oops_exit()', and then call it from
> 'panic()'. And the dumper may dump the same information, which is not
> nice.
> 
> I've looked briefly and tried to figure out how to fix this. But I
> cannot find an clean way. And I was confused by the die/oops/etc code.
> My question is, why the code does not work the following way instead?
> 
> diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
> index 2d8a371..8f322c7 100644
> --- a/arch/x86/kernel/dumpstack.c
> +++ b/arch/x86/kernel/dumpstack.c
> @@ -235,13 +235,12 @@ void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
>         raw_local_irq_restore(flags);
>         oops_exit();
> 
> -       if (!signr)
> -               return;
>         if (in_interrupt())
>                 panic("Fatal exception in interrupt");
>         if (panic_on_oops)
>                 panic("Fatal exception");
> -       do_exit(signr);
> +       if (signr)
> +               do_exit(signr);
>  }
> 
>  int __kprobes __die(const char *str, struct pt_regs *regs, long err)
> 
> If the code worked like this, I think the problem indicated by Atal
> could be easily fixed.
> 

Could as well be, but will not help us much on arch/arm. :)

> > 2. We tried to use panic notifiers mechanism to print additional
> > information that we want to see in mtdoops logs and it worked well,
> > but having the kmsg_dump(KMSG_DUMP_PANIC) before the
> > atomic_notifier_call_chain() breaks this functionality.
> > Can we the call kmsg_dump() after the notifiers had been invoked?
> 
> Atal, I think you should just attach your patch, it is easier to express
> what you mean.
> 
> But for me it looks like atomic_notifier_call_chain() can be moved up.
> 
> Anyway, please, show your patch.
> 

Inlined:


>From 12343c0918853f326b042c6e285b0e184565564f Mon Sep 17 00:00:00 2001
Message-Id:
<12343c0918853f326b042c6e285b0e184565564f.1256223642.git.ext-atal.shargorodsky@nokia.com>
From: Atal Shargorodsky <ext-atal.shargorodsky@nokia.com>
Date: Fri, 2 Oct 2009 17:34:56 +0300
Subject: [PATCH 1/3] debug: introduction of panic info buffer module

The feature of having an option for application to add some data
to be printed at panic could be useful for debugging systems where
the hardware, the kernel, the firmware for supplementary chips, etc.
are under constant development and kernel version does not identify
the exact setup in which the panic occurred.

The way to supply the string is to write it to debugfs file named
panic_info_buff. Currently the buffer length is limited to 1KB - 1B.

Signed-off-by: Atal Shargorodsky <ext-atal.shargorodsky@nokia.com>
---
 drivers/misc/panic_info_buff.c |   92
++++++++++++++++++++++++++++++++++++++++
 1 files changed, 92 insertions(+), 0 deletions(-)
 create mode 100644 drivers/misc/panic_info_buff.c

diff --git a/drivers/misc/panic_info_buff.c
b/drivers/misc/panic_info_buff.c
new file mode 100644
index 0000000..fa6d2b1
--- /dev/null
+++ b/drivers/misc/panic_info_buff.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/notifier.h>
+
+#define PANIC_BUFFER_MAX_LEN  1024
+static char panic_info_buff[PANIC_BUFFER_MAX_LEN];
+static struct dentry *panic_info_buff_debugfs;
+
+static int panic_info_buff_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t panic_info_buff_write(struct file *file,
+		const char __user *buf, size_t len, loff_t *off)
+{
+	if (len >= PANIC_BUFFER_MAX_LEN)
+		return -EINVAL;
+	if (copy_from_user(panic_info_buff, buf, len))
+		return -EFAULT;
+	panic_info_buff[len] = '\0';
+	return len;
+}
+
+static struct file_operations panic_info_buff_fops = {
+	.open   = panic_info_buff_open,
+	.write  = panic_info_buff_write,
+	.llseek = no_llseek,
+	.owner  = THIS_MODULE,
+};
+
+static int panic_info_buff_event(struct notifier_block *this,
+	unsigned long event, void *ptr)
+{
+	if (panic_info_buff[0] == '\0')
+		printk(KERN_EMERG "Panic info buffer is empty.\n");
+	else
+		printk(KERN_EMERG "Panic info buffer:\n"
+				"%s\nBuffer total length: %d characters.\n",
+				panic_info_buff,
+				strlen(panic_info_buff));
+	return NOTIFY_OK;
+}
+
+static struct notifier_block panic_info_buff_block = {
+	.notifier_call  = panic_info_buff_event,
+	.priority       = 1,
+};
+
+static int __devinit panic_info_buff_init(void)
+{
+	panic_info_buff_debugfs = debugfs_create_file("panic_info_buff",
+		S_IFREG | S_IWUSR | S_IWGRP,
+		NULL, NULL, &panic_info_buff_fops);
+	atomic_notifier_chain_register(&panic_notifier_list,
+		&panic_info_buff_block);
+	return 0;
+}
+module_init(panic_info_buff_init);
+
+static void __devexit panic_info_buff_exit(void)
+{
+	debugfs_remove(panic_info_buff_debugfs);
+	atomic_notifier_chain_unregister(&panic_notifier_list,
+		&panic_info_buff_block);
+
+}
+module_exit(panic_info_buff_exit);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("panic_info_buff");
-- 
1.5.4.3




^ permalink raw reply related	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-26 10:40                                   ` Shargorodsky Atal (EXT-Teleca/Helsinki)
  0 siblings, 0 replies; 94+ messages in thread
From: Shargorodsky Atal (EXT-Teleca/Helsinki) @ 2009-10-26 10:40 UTC (permalink / raw)
  To: dedekind1
  Cc: David Woodhouse, LKML, Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Simon Kagstrom, Andrew Morton, Linus Torvalds,
	Ingo Molnar, Alan Cox

On Sat, 2009-10-24 at 19:05 +0200, Artem Bityutskiy wrote:
> On Fri, 2009-10-23 at 18:53 +0300, Shargorodsky Atal
> (EXT-Teleca/Helsinki) wrote:
> > Hi all,
> > 
> > On Thu, 2009-10-22 at 08:25 +0200, ext Simon Kagstrom wrote:
> > 
> > > Thanks to everyone for the reviewing and suggestions!
> > > 
> > 
> > I have a couple of questions:
> > 
> > 1. If somebody writes a module that uses dumper for uploading the
> > oopses/panics logs via some pay-per-byte medium,  since he has no way
> > to know in a module if the panic_on_oops flag is set, he'll have
> > to upload both oops and the following panic, because he does not
> > know for sure that the panic was caused by the oops. Hence he
> > pays twice for the same information, right?
> 
> Looks like a valid point to me. Indeed, in this case we will first call
> 'kmsg_dump(KMSG_DUMP_OOPS)' from 'oops_exit()', and then call it from
> 'panic()'. And the dumper may dump the same information, which is not
> nice.
> 
> I've looked briefly and tried to figure out how to fix this. But I
> cannot find an clean way. And I was confused by the die/oops/etc code.
> My question is, why the code does not work the following way instead?
> 
> diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
> index 2d8a371..8f322c7 100644
> --- a/arch/x86/kernel/dumpstack.c
> +++ b/arch/x86/kernel/dumpstack.c
> @@ -235,13 +235,12 @@ void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
>         raw_local_irq_restore(flags);
>         oops_exit();
> 
> -       if (!signr)
> -               return;
>         if (in_interrupt())
>                 panic("Fatal exception in interrupt");
>         if (panic_on_oops)
>                 panic("Fatal exception");
> -       do_exit(signr);
> +       if (signr)
> +               do_exit(signr);
>  }
> 
>  int __kprobes __die(const char *str, struct pt_regs *regs, long err)
> 
> If the code worked like this, I think the problem indicated by Atal
> could be easily fixed.
> 

Could as well be, but will not help us much on arch/arm. :)

> > 2. We tried to use panic notifiers mechanism to print additional
> > information that we want to see in mtdoops logs and it worked well,
> > but having the kmsg_dump(KMSG_DUMP_PANIC) before the
> > atomic_notifier_call_chain() breaks this functionality.
> > Can we the call kmsg_dump() after the notifiers had been invoked?
> 
> Atal, I think you should just attach your patch, it is easier to express
> what you mean.
> 
> But for me it looks like atomic_notifier_call_chain() can be moved up.
> 
> Anyway, please, show your patch.
> 

Inlined:


>From 12343c0918853f326b042c6e285b0e184565564f Mon Sep 17 00:00:00 2001
Message-Id:
<12343c0918853f326b042c6e285b0e184565564f.1256223642.git.ext-atal.shargorodsky@nokia.com>
From: Atal Shargorodsky <ext-atal.shargorodsky@nokia.com>
Date: Fri, 2 Oct 2009 17:34:56 +0300
Subject: [PATCH 1/3] debug: introduction of panic info buffer module

The feature of having an option for application to add some data
to be printed at panic could be useful for debugging systems where
the hardware, the kernel, the firmware for supplementary chips, etc.
are under constant development and kernel version does not identify
the exact setup in which the panic occurred.

The way to supply the string is to write it to debugfs file named
panic_info_buff. Currently the buffer length is limited to 1KB - 1B.

Signed-off-by: Atal Shargorodsky <ext-atal.shargorodsky@nokia.com>
---
 drivers/misc/panic_info_buff.c |   92
++++++++++++++++++++++++++++++++++++++++
 1 files changed, 92 insertions(+), 0 deletions(-)
 create mode 100644 drivers/misc/panic_info_buff.c

diff --git a/drivers/misc/panic_info_buff.c
b/drivers/misc/panic_info_buff.c
new file mode 100644
index 0000000..fa6d2b1
--- /dev/null
+++ b/drivers/misc/panic_info_buff.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/notifier.h>
+
+#define PANIC_BUFFER_MAX_LEN  1024
+static char panic_info_buff[PANIC_BUFFER_MAX_LEN];
+static struct dentry *panic_info_buff_debugfs;
+
+static int panic_info_buff_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t panic_info_buff_write(struct file *file,
+		const char __user *buf, size_t len, loff_t *off)
+{
+	if (len >= PANIC_BUFFER_MAX_LEN)
+		return -EINVAL;
+	if (copy_from_user(panic_info_buff, buf, len))
+		return -EFAULT;
+	panic_info_buff[len] = '\0';
+	return len;
+}
+
+static struct file_operations panic_info_buff_fops = {
+	.open   = panic_info_buff_open,
+	.write  = panic_info_buff_write,
+	.llseek = no_llseek,
+	.owner  = THIS_MODULE,
+};
+
+static int panic_info_buff_event(struct notifier_block *this,
+	unsigned long event, void *ptr)
+{
+	if (panic_info_buff[0] == '\0')
+		printk(KERN_EMERG "Panic info buffer is empty.\n");
+	else
+		printk(KERN_EMERG "Panic info buffer:\n"
+				"%s\nBuffer total length: %d characters.\n",
+				panic_info_buff,
+				strlen(panic_info_buff));
+	return NOTIFY_OK;
+}
+
+static struct notifier_block panic_info_buff_block = {
+	.notifier_call  = panic_info_buff_event,
+	.priority       = 1,
+};
+
+static int __devinit panic_info_buff_init(void)
+{
+	panic_info_buff_debugfs = debugfs_create_file("panic_info_buff",
+		S_IFREG | S_IWUSR | S_IWGRP,
+		NULL, NULL, &panic_info_buff_fops);
+	atomic_notifier_chain_register(&panic_notifier_list,
+		&panic_info_buff_block);
+	return 0;
+}
+module_init(panic_info_buff_init);
+
+static void __devexit panic_info_buff_exit(void)
+{
+	debugfs_remove(panic_info_buff_debugfs);
+	atomic_notifier_chain_unregister(&panic_notifier_list,
+		&panic_info_buff_block);
+
+}
+module_exit(panic_info_buff_exit);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("panic_info_buff");
-- 
1.5.4.3

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-26 10:36                                   ` Shargorodsky Atal (EXT-Teleca/Helsinki)
@ 2009-10-26 11:53                                     ` Simon Kagstrom
  -1 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-26 11:53 UTC (permalink / raw)
  To: Shargorodsky Atal (EXT-Teleca/Helsinki)
  Cc: Linus Torvalds, Ingo Molnar, Artem Bityutskiy, linux-mtd,
	David Woodhouse, Andrew Morton, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

On Mon, 26 Oct 2009 12:36:33 +0200
"Shargorodsky Atal (EXT-Teleca/Helsinki)" <ext-atal.shargorodsky@nokia.com> wrote:

> > > I can think of a couple of way to figure it out in the module
> > > itself, but I could not think of any clean way to do it.
> > 
> > This is correct, and the mtdoops driver has some provisions to handle
> > this. First, there is a parameter to the module to specify whether
> > oopses should be dumped at all - I added this for the particular case
> > that someone has panic_on_oops set.
> 
> It takes care of most of the situations, but panic_on_oops
> can be changed any time, even after the module is loaded.

Yes, but this parameter is settable at runtime as well by writing
to /sys/module/mtdoops/parameters/dump_oops.

> > Second, it does not dump oopses directly anyway, but puts it in a work
> > queue. That way, if panic_on_oops is set, it will store the panic but
> > the oops (called from the workqueue) will not get written anyway.
> > 
> 
> AFAIK, mtdoops does not put oopses in a work queue. And if by any chance
> it does, then I think it's wrong and might lead to missed oopses, as
> the oops might be because of the work queues themselves, or it might
> look to the kernel like some non-fatal fault, but actually it's a
> sign of a much more catastrophic failure - IOMMU device garbaging
> memory, for instance.

I was referring to my patches to it, sorry. It's in the patch "[PATCH v7 5/5]:
mtdoops: refactor as a kmsg_dumper" (as well as the parameter to dump
oopses at all).

There are other situations which will make dumping problematic as well,
e.g., crashes in the mtd code, so there are certainly some cases which
will be difficult to catch. But in the panic_on_oops case or
oops-in-interrupt, the oops won't be missed and won't be outputted
twice for mtdoops.


Anyway, I understand your problem and agree that it would be good to
fix. Moving up crash_kexec() and the notifiers will at least fix your
second issue. For the double-output-of-oopses, I don't see a good way
to fix it unless relying on the module to correct it like above.

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-26 11:53                                     ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-26 11:53 UTC (permalink / raw)
  To: Shargorodsky Atal (EXT-Teleca/Helsinki)
  Cc: Artem Bityutskiy, David Woodhouse, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Ingo Molnar, Linus Torvalds, Andrew Morton, Alan Cox

On Mon, 26 Oct 2009 12:36:33 +0200
"Shargorodsky Atal (EXT-Teleca/Helsinki)" <ext-atal.shargorodsky@nokia.com> wrote:

> > > I can think of a couple of way to figure it out in the module
> > > itself, but I could not think of any clean way to do it.
> > 
> > This is correct, and the mtdoops driver has some provisions to handle
> > this. First, there is a parameter to the module to specify whether
> > oopses should be dumped at all - I added this for the particular case
> > that someone has panic_on_oops set.
> 
> It takes care of most of the situations, but panic_on_oops
> can be changed any time, even after the module is loaded.

Yes, but this parameter is settable at runtime as well by writing
to /sys/module/mtdoops/parameters/dump_oops.

> > Second, it does not dump oopses directly anyway, but puts it in a work
> > queue. That way, if panic_on_oops is set, it will store the panic but
> > the oops (called from the workqueue) will not get written anyway.
> > 
> 
> AFAIK, mtdoops does not put oopses in a work queue. And if by any chance
> it does, then I think it's wrong and might lead to missed oopses, as
> the oops might be because of the work queues themselves, or it might
> look to the kernel like some non-fatal fault, but actually it's a
> sign of a much more catastrophic failure - IOMMU device garbaging
> memory, for instance.

I was referring to my patches to it, sorry. It's in the patch "[PATCH v7 5/5]:
mtdoops: refactor as a kmsg_dumper" (as well as the parameter to dump
oopses at all).

There are other situations which will make dumping problematic as well,
e.g., crashes in the mtd code, so there are certainly some cases which
will be difficult to catch. But in the panic_on_oops case or
oops-in-interrupt, the oops won't be missed and won't be outputted
twice for mtdoops.


Anyway, I understand your problem and agree that it would be good to
fix. Moving up crash_kexec() and the notifiers will at least fix your
second issue. For the double-output-of-oopses, I don't see a good way
to fix it unless relying on the module to correct it like above.

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-26 11:53                                     ` Simon Kagstrom
@ 2009-10-26 15:13                                       ` Shargorodsky Atal (EXT-Teleca/Helsinki)
  -1 siblings, 0 replies; 94+ messages in thread
From: Shargorodsky Atal (EXT-Teleca/Helsinki) @ 2009-10-26 15:13 UTC (permalink / raw)
  To: ext Simon Kagstrom
  Cc: Linus Torvalds, Ingo Molnar, Artem Bityutskiy, linux-mtd,
	David Woodhouse, Andrew Morton, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

On Mon, 2009-10-26 at 12:53 +0100, ext Simon Kagstrom wrote:
> On Mon, 26 Oct 2009 12:36:33 +0200
> "Shargorodsky Atal (EXT-Teleca/Helsinki)" <ext-atal.shargorodsky@nokia.com> wrote:
> 
> > > > I can think of a couple of way to figure it out in the module
> > > > itself, but I could not think of any clean way to do it.
> > > 
> > > This is correct, and the mtdoops driver has some provisions to handle
> > > this. First, there is a parameter to the module to specify whether
> > > oopses should be dumped at all - I added this for the particular case
> > > that someone has panic_on_oops set.
> > 
> > It takes care of most of the situations, but panic_on_oops
> > can be changed any time, even after the module is loaded.
> 
> Yes, but this parameter is settable at runtime as well by writing
> to /sys/module/mtdoops/parameters/dump_oops.
> 
> > > Second, it does not dump oopses directly anyway, but puts it in a work
> > > queue. That way, if panic_on_oops is set, it will store the panic but
> > > the oops (called from the workqueue) will not get written anyway.
> > > 
> > 
> > AFAIK, mtdoops does not put oopses in a work queue. And if by any chance
> > it does, then I think it's wrong and might lead to missed oopses, as
> > the oops might be because of the work queues themselves, or it might
> > look to the kernel like some non-fatal fault, but actually it's a
> > sign of a much more catastrophic failure - IOMMU device garbaging
> > memory, for instance.
> 
> I was referring to my patches to it, sorry. It's in the patch "[PATCH v7 5/5]:
> mtdoops: refactor as a kmsg_dumper" (as well as the parameter to dump
> oopses at all).
> 
> There are other situations which will make dumping problematic as well,
> e.g., crashes in the mtd code, so there are certainly some cases which
> will be difficult to catch. But in the panic_on_oops case or
> oops-in-interrupt, the oops won't be missed and won't be outputted
> twice for mtdoops.
> 
> 
> Anyway, I understand your problem and agree that it would be good to
> fix. Moving up crash_kexec() and the notifiers will at least fix your
> second issue. For the double-output-of-oopses, I don't see a good way
> to fix it unless relying on the module to correct it like above.
> 

How about adding KMSG_DUMP_LAST_OOPS_BEFORE_PANIC or something to the
kmsg_dump_reason enum, and making the kmsg_dump look like
kmsg_dump(panic_on_oops ? KMSG_DUMP_LAST_OOPS_BEFORE_PANIC : KMSG_DUMP_OOPS);
in oops_exit. Then let the dumpers decide what they want to do about it.
Just a thought.

And since you have no objections about moving notifiers up, it looks
like the second issue will be resolved, I believe Artem
will take care of it. :)

Thanks a lot,
Atal.

> // Simon


^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-26 15:13                                       ` Shargorodsky Atal (EXT-Teleca/Helsinki)
  0 siblings, 0 replies; 94+ messages in thread
From: Shargorodsky Atal (EXT-Teleca/Helsinki) @ 2009-10-26 15:13 UTC (permalink / raw)
  To: ext Simon Kagstrom
  Cc: Artem Bityutskiy, David Woodhouse, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Ingo Molnar, Linus Torvalds, Andrew Morton, Alan Cox

On Mon, 2009-10-26 at 12:53 +0100, ext Simon Kagstrom wrote:
> On Mon, 26 Oct 2009 12:36:33 +0200
> "Shargorodsky Atal (EXT-Teleca/Helsinki)" <ext-atal.shargorodsky@nokia.com> wrote:
> 
> > > > I can think of a couple of way to figure it out in the module
> > > > itself, but I could not think of any clean way to do it.
> > > 
> > > This is correct, and the mtdoops driver has some provisions to handle
> > > this. First, there is a parameter to the module to specify whether
> > > oopses should be dumped at all - I added this for the particular case
> > > that someone has panic_on_oops set.
> > 
> > It takes care of most of the situations, but panic_on_oops
> > can be changed any time, even after the module is loaded.
> 
> Yes, but this parameter is settable at runtime as well by writing
> to /sys/module/mtdoops/parameters/dump_oops.
> 
> > > Second, it does not dump oopses directly anyway, but puts it in a work
> > > queue. That way, if panic_on_oops is set, it will store the panic but
> > > the oops (called from the workqueue) will not get written anyway.
> > > 
> > 
> > AFAIK, mtdoops does not put oopses in a work queue. And if by any chance
> > it does, then I think it's wrong and might lead to missed oopses, as
> > the oops might be because of the work queues themselves, or it might
> > look to the kernel like some non-fatal fault, but actually it's a
> > sign of a much more catastrophic failure - IOMMU device garbaging
> > memory, for instance.
> 
> I was referring to my patches to it, sorry. It's in the patch "[PATCH v7 5/5]:
> mtdoops: refactor as a kmsg_dumper" (as well as the parameter to dump
> oopses at all).
> 
> There are other situations which will make dumping problematic as well,
> e.g., crashes in the mtd code, so there are certainly some cases which
> will be difficult to catch. But in the panic_on_oops case or
> oops-in-interrupt, the oops won't be missed and won't be outputted
> twice for mtdoops.
> 
> 
> Anyway, I understand your problem and agree that it would be good to
> fix. Moving up crash_kexec() and the notifiers will at least fix your
> second issue. For the double-output-of-oopses, I don't see a good way
> to fix it unless relying on the module to correct it like above.
> 

How about adding KMSG_DUMP_LAST_OOPS_BEFORE_PANIC or something to the
kmsg_dump_reason enum, and making the kmsg_dump look like
kmsg_dump(panic_on_oops ? KMSG_DUMP_LAST_OOPS_BEFORE_PANIC : KMSG_DUMP_OOPS);
in oops_exit. Then let the dumpers decide what they want to do about it.
Just a thought.

And since you have no objections about moving notifiers up, it looks
like the second issue will be resolved, I believe Artem
will take care of it. :)

Thanks a lot,
Atal.

> // Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
  2009-10-26 15:13                                       ` Shargorodsky Atal (EXT-Teleca/Helsinki)
@ 2009-10-26 15:37                                         ` Simon Kagstrom
  -1 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-26 15:37 UTC (permalink / raw)
  To: Shargorodsky Atal (EXT-Teleca/Helsinki)
  Cc: Linus Torvalds, Ingo Molnar, Artem Bityutskiy, linux-mtd,
	David Woodhouse, Andrew Morton, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	Alan Cox

On Mon, 26 Oct 2009 17:13:27 +0200
"Shargorodsky Atal (EXT-Teleca/Helsinki)" <ext-atal.shargorodsky@nokia.com> wrote:

> How about adding KMSG_DUMP_LAST_OOPS_BEFORE_PANIC or something to the
> kmsg_dump_reason enum, and making the kmsg_dump look like
> kmsg_dump(panic_on_oops ? KMSG_DUMP_LAST_OOPS_BEFORE_PANIC : KMSG_DUMP_OOPS);
> in oops_exit. Then let the dumpers decide what they want to do about it.
> Just a thought.

It would also have to take in_interrupt() in account since that will
also lead to a panic.

> And since you have no objections about moving notifiers up, it looks
> like the second issue will be resolved, I believe Artem
> will take care of it. :)

Well, I have no objections to it, but I also know very little of the
reasoning to put it there in the first place, so don't count my vote
for very much here :-)

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v11 4/5] core: Add kernel message dumper to call on oopses and panics
@ 2009-10-26 15:37                                         ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-26 15:37 UTC (permalink / raw)
  To: Shargorodsky Atal (EXT-Teleca/Helsinki)
  Cc: Artem Bityutskiy, David Woodhouse, LKML,
	Koskinen Aaro (Nokia-D/Helsinki),
	linux-mtd, Ingo Molnar, Linus Torvalds, Andrew Morton, Alan Cox

On Mon, 26 Oct 2009 17:13:27 +0200
"Shargorodsky Atal (EXT-Teleca/Helsinki)" <ext-atal.shargorodsky@nokia.com> wrote:

> How about adding KMSG_DUMP_LAST_OOPS_BEFORE_PANIC or something to the
> kmsg_dump_reason enum, and making the kmsg_dump look like
> kmsg_dump(panic_on_oops ? KMSG_DUMP_LAST_OOPS_BEFORE_PANIC : KMSG_DUMP_OOPS);
> in oops_exit. Then let the dumpers decide what they want to do about it.
> Just a thought.

It would also have to take in_interrupt() in account since that will
also lead to a panic.

> And since you have no objections about moving notifiers up, it looks
> like the second issue will be resolved, I believe Artem
> will take care of it. :)

Well, I have no objections to it, but I also know very little of the
reasoning to put it there in the first place, so don't count my vote
for very much here :-)

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v12 0/4]: mtdoops: fixes and improvements
  2009-10-15  7:40 [PATCH v7 0/5]: mtdoops: fixes and improvements Simon Kagstrom
                   ` (4 preceding siblings ...)
  2009-10-15  7:48 ` [PATCH v7 5/5]: mtdoops: refactor as a kmsg_dumper Simon Kagstrom
@ 2009-10-29 12:35 ` Simon Kagstrom
  2009-10-29 12:41   ` [PATCH v12 1/4]: mtdoops: Keep track of used/unused mtdoops pages in an array Simon Kagstrom
                     ` (3 more replies)
  5 siblings, 4 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-29 12:35 UTC (permalink / raw)
  To: Artem Bityutskiy, linux-mtd

Hi again!

Here is another round of the mtdoops fixes for Artems tree. The patches
are:

1. Keep track of mtdoops page cleanliness in an array. This allows
   mtdoops_inc_counter to be called during panic (which fails in my
   case with the current code in mtd->read, although I believe this is
   MTD-driver dependent).

2. Add a maximum MTD partition size for mtdoops.

3. Make page size configurable to support longer messages. Mainly
   needed for patch 4, but also allows longer messages to be stored
   during panics (when the next oops area cannot be erased).

4. Refactor mtdoops as a kmsg_dumper device instead of a console device.

Apart from the changelog in each patch, the patch that removes the
always-erase-empty-areas has been dropped.

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* [PATCH v12 1/4]: mtdoops: Keep track of used/unused mtdoops pages in an array
  2009-10-29 12:35 ` [PATCH v12 0/4]: mtdoops: fixes and improvements Simon Kagstrom
@ 2009-10-29 12:41   ` Simon Kagstrom
  2009-10-29 15:24     ` Artem Bityutskiy
  2009-10-29 12:41   ` [PATCH v12 2/4]: mtdoops: Add a maximum MTD partition size Simon Kagstrom
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-29 12:41 UTC (permalink / raw)
  To: Artem Bityutskiy, linux-mtd

This patch makes mtdoops keep track of used/unused pages in an array
instead of scanning the flash after a write. The advantage with this
approach is that it avoids calling mtd->read on a panic, which is not
possible for all mtd drivers.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
---
 drivers/mtd/mtdoops.c |   62 ++++++++++++++++++++++++++++++++++--------------
 1 files changed, 44 insertions(+), 18 deletions(-)

diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 18c6c96..209f8f4 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -44,6 +44,7 @@ static struct mtdoops_context {
 	int oops_pages;
 	int nextpage;
 	int nextcount;
+	unsigned long *oops_page_used;
 	char *name;
 
 	void *oops_buf;
@@ -54,18 +55,38 @@ static struct mtdoops_context {
 	int writecount;
 } oops_cxt;
 
+static void mark_page_used(struct mtdoops_context *cxt, int page)
+{
+	set_bit(page, cxt->oops_page_used);
+}
+
+static void mark_page_unused(struct mtdoops_context *cxt, int page)
+{
+	clear_bit(page, cxt->oops_page_used);
+}
+
+static int page_is_used(struct mtdoops_context *cxt, int page)
+{
+	return test_bit(page, cxt->oops_page_used);
+}
+
 static void mtdoops_erase_callback(struct erase_info *done)
 {
 	wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
 	wake_up(wait_q);
 }
 
-static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
+static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
 {
+	struct mtd_info *mtd = cxt->mtd;
+	u32 start_page_offset = mtd_div_by_eb(offset, mtd) * mtd->erasesize;
+	u32 start_page = start_page_offset / OOPS_PAGE_SIZE;
+	u32 erase_pages = mtd->erasesize / OOPS_PAGE_SIZE;
 	struct erase_info erase;
 	DECLARE_WAITQUEUE(wait, current);
 	wait_queue_head_t wait_q;
 	int ret;
+	int page;
 
 	init_waitqueue_head(&wait_q);
 	erase.mtd = mtd;
@@ -90,16 +111,15 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
 	schedule();  /* Wait for erase to finish. */
 	remove_wait_queue(&wait_q, &wait);
 
+	/* Mark pages as unused */
+	for (page = start_page; page < start_page + erase_pages; page++)
+		mark_page_unused(cxt, page);
+
 	return 0;
 }
 
 static void mtdoops_inc_counter(struct mtdoops_context *cxt)
 {
-	struct mtd_info *mtd = cxt->mtd;
-	size_t retlen;
-	u32 count;
-	int ret;
-
 	cxt->nextpage++;
 	if (cxt->nextpage >= cxt->oops_pages)
 		cxt->nextpage = 0;
@@ -107,17 +127,7 @@ static void mtdoops_inc_counter(struct mtdoops_context *cxt)
 	if (cxt->nextcount == 0xffffffff)
 		cxt->nextcount = 0;
 
-	ret = mtd->read(mtd, cxt->nextpage * OOPS_PAGE_SIZE, 4,
-			&retlen, (u_char *) &count);
-	if (retlen != 4 || (ret < 0 && ret != -EUCLEAN)) {
-		printk(KERN_ERR "mtdoops: read failure at %d (%td of 4 read), err %d\n",
-		       cxt->nextpage * OOPS_PAGE_SIZE, retlen, ret);
-		schedule_work(&cxt->work_erase);
-		return;
-	}
-
-	/* See if we need to erase the next block */
-	if (count != 0xffffffff) {
+	if (page_is_used(cxt, cxt->nextpage)) {
 		schedule_work(&cxt->work_erase);
 		return;
 	}
@@ -168,7 +178,7 @@ badblock:
 	}
 
 	for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
-		ret = mtdoops_erase_block(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+		ret = mtdoops_erase_block(cxt, cxt->nextpage * OOPS_PAGE_SIZE);
 
 	if (ret >= 0) {
 		printk(KERN_DEBUG "mtdoops: ready %d, %d\n",
@@ -209,6 +219,7 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 	if (retlen != OOPS_PAGE_SIZE || ret < 0)
 		printk(KERN_ERR "mtdoops: write failure at %d (%td of %d written), error %d\n",
 		       cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret);
+	mark_page_used(cxt, cxt->nextpage);
 
 	mtdoops_inc_counter(cxt);
 }
@@ -230,6 +241,8 @@ static void find_next_position(struct mtdoops_context *cxt)
 	size_t retlen;
 
 	for (page = 0; page < cxt->oops_pages; page++) {
+		/* Assume the page is used */
+		mark_page_used(cxt, page);
 		ret = mtd->read(mtd, page * OOPS_PAGE_SIZE, 8, &retlen, (u_char *) &count[0]);
 		if (retlen != 8 || (ret < 0 && ret != -EUCLEAN)) {
 			printk(KERN_ERR "mtdoops: read failure at %d (%td of 8 read), err %d\n",
@@ -237,6 +250,8 @@ static void find_next_position(struct mtdoops_context *cxt)
 			continue;
 		}
 
+		if (count[0] == 0xffffffff && count[1] == 0xffffffff)
+			mark_page_unused(cxt, page);
 		if (count[1] != MTDOOPS_KERNMSG_MAGIC)
 			continue;
 		if (count[0] == 0xffffffff)
@@ -273,6 +288,9 @@ static void find_next_position(struct mtdoops_context *cxt)
 static void mtdoops_notify_add(struct mtd_info *mtd)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
+	u64 mtdoops_pages = mtd->size;
+
+	do_div(mtdoops_pages, OOPS_PAGE_SIZE);
 
 	if (cxt->name && !strcmp(mtd->name, cxt->name))
 		cxt->mtd_index = mtd->index;
@@ -292,6 +310,13 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		return;
 	}
 
+	/* oops_page_used is a bit field */
+	cxt->oops_page_used = vmalloc(DIV_ROUND_UP(mtdoops_pages,
+			BITS_PER_LONG));
+	if (!cxt->oops_page_used) {
+		printk(KERN_ERR "Could not allocate page array\n");
+		return;
+	}
 	cxt->mtd = mtd;
 	if (mtd->size > INT_MAX)
 		cxt->oops_pages = INT_MAX / OOPS_PAGE_SIZE;
@@ -444,6 +469,7 @@ static void __exit mtdoops_console_exit(void)
 	unregister_console(&mtdoops_console);
 	kfree(cxt->name);
 	vfree(cxt->oops_buf);
+	vfree(cxt->oops_page_used);
 }
 
 
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v12 2/4]: mtdoops: Add a maximum MTD partition size
  2009-10-29 12:35 ` [PATCH v12 0/4]: mtdoops: fixes and improvements Simon Kagstrom
  2009-10-29 12:41   ` [PATCH v12 1/4]: mtdoops: Keep track of used/unused mtdoops pages in an array Simon Kagstrom
@ 2009-10-29 12:41   ` Simon Kagstrom
  2009-10-29 15:27     ` Artem Bityutskiy
  2009-11-03  6:23     ` Artem Bityutskiy
  2009-10-29 12:41   ` [PATCH v12 3/4]: mtdoops: Make page (record) size configurable Simon Kagstrom
  2009-10-29 12:41   ` [PATCH v12 4/4]: mtdoops: refactor as a kmsg_dumper Simon Kagstrom
  3 siblings, 2 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-29 12:41 UTC (permalink / raw)
  To: Artem Bityutskiy, linux-mtd

A configurable maximum MTD partition size for mtdoops avoids mistakes
where the user gives e.g., a rootfs partition to mtdoops (which will
happily erase it).

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
---
 drivers/mtd/Kconfig   |   13 +++++++++++++
 drivers/mtd/mtdoops.c |   11 +++++++----
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index ecf90f5..9a69af8 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -315,6 +315,19 @@ config MTD_OOPS
 	  To use, add console=ttyMTDx to the kernel command line,
 	  where x is the MTD device number to use.
 
+config MTD_OOPS_MAX_MTD_SIZE
+	int "Maximum MTD oops partition size (kbytes)"
+	default 4096
+	range 8 1048576
+	depends on MTD_OOPS
+	help
+	  This parameter sets the maximum MTD partition size for use with
+	  MTD oops. The default value is used as a safeguard against using
+	  e.g., a root filesystem partition as a MTDoops device (in which
+	  case it will be erased).
+
+	  No need to change unless you have a very large MTDoops partition.
+
 source "drivers/mtd/chips/Kconfig"
 
 source "drivers/mtd/maps/Kconfig"
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 209f8f4..dc94a70 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -298,6 +298,12 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 	if (mtd->index != cxt->mtd_index || cxt->mtd_index < 0)
 		return;
 
+	if (mtd->size > CONFIG_MTD_OOPS_MAX_MTD_SIZE * 1024) {
+		printk(KERN_ERR "mtdoops: MTD partition %d too big for mtdoops (limit %d KiB)\n",
+		       mtd->index, CONFIG_MTD_OOPS_MAX_MTD_SIZE);
+		return;
+	}
+
 	if (mtd->size < mtd->erasesize * 2) {
 		printk(KERN_ERR "mtdoops: MTD partition %d not big enough for mtdoops\n",
 		       mtd->index);
@@ -318,10 +324,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		return;
 	}
 	cxt->mtd = mtd;
-	if (mtd->size > INT_MAX)
-		cxt->oops_pages = INT_MAX / OOPS_PAGE_SIZE;
-	else
-		cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE;
+	cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE;
 
 	find_next_position(cxt);
 
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v12 3/4]: mtdoops: Make page (record) size configurable
  2009-10-29 12:35 ` [PATCH v12 0/4]: mtdoops: fixes and improvements Simon Kagstrom
  2009-10-29 12:41   ` [PATCH v12 1/4]: mtdoops: Keep track of used/unused mtdoops pages in an array Simon Kagstrom
  2009-10-29 12:41   ` [PATCH v12 2/4]: mtdoops: Add a maximum MTD partition size Simon Kagstrom
@ 2009-10-29 12:41   ` Simon Kagstrom
  2009-11-03  6:23     ` Artem Bityutskiy
  2009-10-29 12:41   ` [PATCH v12 4/4]: mtdoops: refactor as a kmsg_dumper Simon Kagstrom
  3 siblings, 1 reply; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-29 12:41 UTC (permalink / raw)
  To: Artem Bityutskiy, linux-mtd

The main justification for this is to allow catching long messages
during a panic, where the top part might otherwise be lost since moving
to the next block can require a flash erase.

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
---
ChangeLog:
 * Rebased over "[PATCH v12 2/4]: mtdoops: Add a maximum MTD partition size"

 drivers/mtd/mtdoops.c |   75 ++++++++++++++++++++++++++++--------------------
 1 files changed, 44 insertions(+), 31 deletions(-)

diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index dc94a70..6c8aa70 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -34,7 +34,11 @@
 #include <linux/mtd/mtd.h>
 
 #define MTDOOPS_KERNMSG_MAGIC 0x5d005d00
-#define OOPS_PAGE_SIZE 4096
+
+static unsigned long record_size = 4096;
+module_param(record_size, ulong, 0400);
+MODULE_PARM_DESC(record_size,
+		"record size for MTD OOPS pages in bytes (default 4096)");
 
 static struct mtdoops_context {
 	int mtd_index;
@@ -80,8 +84,8 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
 {
 	struct mtd_info *mtd = cxt->mtd;
 	u32 start_page_offset = mtd_div_by_eb(offset, mtd) * mtd->erasesize;
-	u32 start_page = start_page_offset / OOPS_PAGE_SIZE;
-	u32 erase_pages = mtd->erasesize / OOPS_PAGE_SIZE;
+	u32 start_page = start_page_offset / record_size;
+	u32 erase_pages = mtd->erasesize / record_size;
 	struct erase_info erase;
 	DECLARE_WAITQUEUE(wait, current);
 	wait_queue_head_t wait_q;
@@ -149,15 +153,15 @@ static void mtdoops_workfunc_erase(struct work_struct *work)
 	if (!mtd)
 		return;
 
-	mod = (cxt->nextpage * OOPS_PAGE_SIZE) % mtd->erasesize;
+	mod = (cxt->nextpage * record_size) % mtd->erasesize;
 	if (mod != 0) {
-		cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / OOPS_PAGE_SIZE);
+		cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / record_size);
 		if (cxt->nextpage >= cxt->oops_pages)
 			cxt->nextpage = 0;
 	}
 
 	while (mtd->block_isbad) {
-		ret = mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+		ret = mtd->block_isbad(mtd, cxt->nextpage * record_size);
 		if (!ret)
 			break;
 		if (ret < 0) {
@@ -165,20 +169,20 @@ static void mtdoops_workfunc_erase(struct work_struct *work)
 			return;
 		}
 badblock:
-		printk(KERN_WARNING "mtdoops: bad block at %08x\n",
-		       cxt->nextpage * OOPS_PAGE_SIZE);
+		printk(KERN_WARNING "mtdoops: bad block at %08lx\n",
+		       cxt->nextpage * record_size);
 		i++;
-		cxt->nextpage = cxt->nextpage + (mtd->erasesize / OOPS_PAGE_SIZE);
+		cxt->nextpage = cxt->nextpage + (mtd->erasesize / record_size);
 		if (cxt->nextpage >= cxt->oops_pages)
 			cxt->nextpage = 0;
-		if (i == cxt->oops_pages / (mtd->erasesize / OOPS_PAGE_SIZE)) {
+		if (i == cxt->oops_pages / (mtd->erasesize / record_size)) {
 			printk(KERN_ERR "mtdoops: all blocks bad!\n");
 			return;
 		}
 	}
 
 	for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
-		ret = mtdoops_erase_block(cxt, cxt->nextpage * OOPS_PAGE_SIZE);
+		ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size);
 
 	if (ret >= 0) {
 		printk(KERN_DEBUG "mtdoops: ready %d, %d\n",
@@ -188,7 +192,7 @@ badblock:
 	}
 
 	if (mtd->block_markbad && ret == -EIO) {
-		ret = mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+		ret = mtd->block_markbad(mtd, cxt->nextpage * record_size);
 		if (ret < 0) {
 			printk(KERN_ERR "mtdoops: block_markbad failed, aborting\n");
 			return;
@@ -203,22 +207,22 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 	size_t retlen;
 	int ret;
 
-	if (cxt->writecount < OOPS_PAGE_SIZE)
+	if (cxt->writecount < record_size)
 		memset(cxt->oops_buf + cxt->writecount, 0xff,
-					OOPS_PAGE_SIZE - cxt->writecount);
+					record_size - cxt->writecount);
 
 	if (panic)
-		ret = mtd->panic_write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
-					OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+		ret = mtd->panic_write(mtd, cxt->nextpage * record_size,
+					record_size, &retlen, cxt->oops_buf);
 	else
-		ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
-					OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+		ret = mtd->write(mtd, cxt->nextpage * record_size,
+					record_size, &retlen, cxt->oops_buf);
 
 	cxt->writecount = 0;
 
-	if (retlen != OOPS_PAGE_SIZE || ret < 0)
-		printk(KERN_ERR "mtdoops: write failure at %d (%td of %d written), error %d\n",
-		       cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret);
+	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);
 	mark_page_used(cxt, cxt->nextpage);
 
 	mtdoops_inc_counter(cxt);
@@ -243,10 +247,10 @@ static void find_next_position(struct mtdoops_context *cxt)
 	for (page = 0; page < cxt->oops_pages; page++) {
 		/* Assume the page is used */
 		mark_page_used(cxt, page);
-		ret = mtd->read(mtd, page * OOPS_PAGE_SIZE, 8, &retlen, (u_char *) &count[0]);
+		ret = mtd->read(mtd, page * record_size, 8, &retlen, (u_char *) &count[0]);
 		if (retlen != 8 || (ret < 0 && ret != -EUCLEAN)) {
-			printk(KERN_ERR "mtdoops: read failure at %d (%td of 8 read), err %d\n",
-			       page * OOPS_PAGE_SIZE, retlen, ret);
+			printk(KERN_ERR "mtdoops: read failure at %ld (%td of 8 read), err %d\n",
+			       page * record_size, retlen, ret);
 			continue;
 		}
 
@@ -290,7 +294,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 	struct mtdoops_context *cxt = &oops_cxt;
 	u64 mtdoops_pages = mtd->size;
 
-	do_div(mtdoops_pages, OOPS_PAGE_SIZE);
+	do_div(mtdoops_pages, record_size);
 
 	if (cxt->name && !strcmp(mtd->name, cxt->name))
 		cxt->mtd_index = mtd->index;
@@ -310,7 +314,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		return;
 	}
 
-	if (mtd->erasesize < OOPS_PAGE_SIZE) {
+	if (mtd->erasesize < record_size) {
 		printk(KERN_ERR "mtdoops: eraseblock size of MTD partition %d too small\n",
 		       mtd->index);
 		return;
@@ -324,7 +328,8 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		return;
 	}
 	cxt->mtd = mtd;
-	cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE;
+
+	cxt->oops_pages = (int)mtd->size / record_size;
 
 	find_next_position(cxt);
 
@@ -401,15 +406,15 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
 		cxt->writecount = 8;
 	}
 
-	if (count + cxt->writecount > OOPS_PAGE_SIZE)
-		count = OOPS_PAGE_SIZE - cxt->writecount;
+	if (count + cxt->writecount > record_size)
+		count = record_size - cxt->writecount;
 
 	memcpy(cxt->oops_buf + cxt->writecount, s, count);
 	cxt->writecount += count;
 
 	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
 
-	if (cxt->writecount == OOPS_PAGE_SIZE)
+	if (cxt->writecount == record_size)
 		mtdoops_console_sync();
 }
 
@@ -448,8 +453,16 @@ static int __init mtdoops_console_init(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
 
+	if ((record_size & 4095) != 0) {
+		printk(KERN_ERR "mtdoops: record_size must be a multiple of 4096\n");
+		return -EINVAL;
+	}
+	if (record_size < 4096) {
+		printk(KERN_ERR "mtdoops: record_size must be over 4096 bytes\n");
+		return -EINVAL;
+	}
 	cxt->mtd_index = -1;
-	cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE);
+	cxt->oops_buf = vmalloc(record_size);
 	if (!cxt->oops_buf) {
 		printk(KERN_ERR "mtdoops: failed to allocate buffer workspace\n");
 		return -ENOMEM;
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v12 4/4]: mtdoops: refactor as a kmsg_dumper
  2009-10-29 12:35 ` [PATCH v12 0/4]: mtdoops: fixes and improvements Simon Kagstrom
                     ` (2 preceding siblings ...)
  2009-10-29 12:41   ` [PATCH v12 3/4]: mtdoops: Make page (record) size configurable Simon Kagstrom
@ 2009-10-29 12:41   ` Simon Kagstrom
  2009-11-03  7:29     ` Artem Bityutskiy
  3 siblings, 1 reply; 94+ messages in thread
From: Simon Kagstrom @ 2009-10-29 12:41 UTC (permalink / raw)
  To: Artem Bityutskiy, linux-mtd

The last messages which happens before a crash might contain interesting
information about the crash. This patch reworks mtdoops using the
kmsg_dumper support instead of a console, which simplifies the code and
also includes the messages before the oops started.

On oops callbacks, the MTD device write is scheduled in a work queue (to
be able to use the regular mtd->write call), while panics call
mtd->panic_write directly. Thus, if panic_on_oops is set, the oops will
be written out during the panic.

A parameter to specify which mtd device to use (number or name), as well
as a flag, writable at runtime, to toggle wheter to dump oopses or only
panics (since oopses can often be handled by regular syslog).

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
---
ChangeLog:
  * Rebased on top of "[PATCH v12 3/4]: mtdoops: Make page (record) size configurable"

 drivers/mtd/Kconfig   |    5 +-
 drivers/mtd/mtdoops.c |  218 +++++++++++++++++++++----------------------------
 2 files changed, 96 insertions(+), 127 deletions(-)

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 9a69af8..c1bcad5 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -312,8 +312,9 @@ config MTD_OOPS
 	  buffer in a flash partition where it can be read back at some
 	  later point.
 
-	  To use, add console=ttyMTDx to the kernel command line,
-	  where x is the MTD device number to use.
+	  To use, add mtddev=name/number to the kernel command line,
+	  where name/number is the name or number of the MTD device
+	  to use (e.g., mtddev=7 for /dev/mtd7).
 
 config MTD_OOPS_MAX_MTD_SIZE
 	int "Maximum MTD oops partition size (kbytes)"
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 6c8aa70..91b0061 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -29,18 +29,31 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/delay.h>
-#include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
+#include <linux/kmsg_dump.h>
 
 #define MTDOOPS_KERNMSG_MAGIC 0x5d005d00
+#define MTDOOPS_HEADER_SIZE   8
 
 static unsigned long record_size = 4096;
 module_param(record_size, ulong, 0400);
 MODULE_PARM_DESC(record_size,
 		"record size for MTD OOPS pages in bytes (default 4096)");
 
+static char mtddev[80];
+module_param_string(mtddev, mtddev, 80, 0400);
+MODULE_PARM_DESC(mtddev,
+		"name or index number of the MTD device to use");
+
+static int dump_oops = 1;
+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 struct mtdoops_context {
+	struct kmsg_dumper dump;
+
 	int mtd_index;
 	struct work_struct work_erase;
 	struct work_struct work_write;
@@ -49,14 +62,8 @@ static struct mtdoops_context {
 	int nextpage;
 	int nextcount;
 	unsigned long *oops_page_used;
-	char *name;
 
 	void *oops_buf;
-
-	/* writecount and disabling ready are spin lock protected */
-	spinlock_t writecount_lock;
-	int ready;
-	int writecount;
 } oops_cxt;
 
 static void mark_page_used(struct mtdoops_context *cxt, int page)
@@ -108,7 +115,7 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
 		remove_wait_queue(&wait_q, &wait);
 		printk(KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] on \"%s\" failed\n",
 		       (unsigned long long)erase.addr,
-		       (unsigned long long)erase.len, mtd->name);
+		       (unsigned long long)erase.len, mtddev);
 		return ret;
 	}
 
@@ -138,7 +145,6 @@ static void mtdoops_inc_counter(struct mtdoops_context *cxt)
 
 	printk(KERN_DEBUG "mtdoops: ready %d, %d (no erase)\n",
 	       cxt->nextpage, cxt->nextcount);
-	cxt->ready = 1;
 }
 
 /* Scheduled work - when we can't proceed without erasing a block */
@@ -187,7 +193,6 @@ badblock:
 	if (ret >= 0) {
 		printk(KERN_DEBUG "mtdoops: ready %d, %d\n",
 		       cxt->nextpage, cxt->nextcount);
-		cxt->ready = 1;
 		return;
 	}
 
@@ -205,11 +210,13 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 {
 	struct mtd_info *mtd = cxt->mtd;
 	size_t retlen;
+	u32 *hdr;
 	int ret;
 
-	if (cxt->writecount < record_size)
-		memset(cxt->oops_buf + cxt->writecount, 0xff,
-					record_size - cxt->writecount);
+	/* Add mtdoops header to the buffer */
+	hdr = cxt->oops_buf;
+	hdr[0] = cxt->nextcount;
+	hdr[1] = MTDOOPS_KERNMSG_MAGIC;
 
 	if (panic)
 		ret = mtd->panic_write(mtd, cxt->nextpage * record_size,
@@ -218,17 +225,15 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 		ret = mtd->write(mtd, cxt->nextpage * record_size,
 					record_size, &retlen, cxt->oops_buf);
 
-	cxt->writecount = 0;
-
 	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);
 	mark_page_used(cxt, cxt->nextpage);
+	memset(cxt->oops_buf, 0xff, record_size);
 
 	mtdoops_inc_counter(cxt);
 }
 
-
 static void mtdoops_workfunc_write(struct work_struct *work)
 {
 	struct mtdoops_context *cxt =
@@ -247,10 +252,13 @@ static void find_next_position(struct mtdoops_context *cxt)
 	for (page = 0; page < cxt->oops_pages; page++) {
 		/* Assume the page is used */
 		mark_page_used(cxt, page);
-		ret = mtd->read(mtd, page * record_size, 8, &retlen, (u_char *) &count[0]);
-		if (retlen != 8 || (ret < 0 && ret != -EUCLEAN)) {
-			printk(KERN_ERR "mtdoops: read failure at %ld (%td of 8 read), err %d\n",
-			       page * record_size, retlen, ret);
+		ret = mtd->read(mtd, page * record_size, MTDOOPS_HEADER_SIZE,
+				&retlen, (u_char *) &count[0]);
+		if (retlen != MTDOOPS_HEADER_SIZE ||
+				(ret < 0 && ret != -EUCLEAN)) {
+			printk(KERN_ERR "mtdoops: read failure at %ld (%td of %d read), err %d\n",
+			       page * record_size, retlen,
+			       MTDOOPS_HEADER_SIZE, ret);
 			continue;
 		}
 
@@ -288,6 +296,42 @@ 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)
+{
+	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;
+
+	/* 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;
+
+	memcpy(dst, s1 + s1_start, l1_cpy);
+	memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
+
+	/* Panics must be written immediately */
+	if (reason == KMSG_DUMP_PANIC) {
+		if (!cxt->mtd->panic_write)
+			printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n");
+		else
+			mtdoops_write(cxt, 1);
+		return;
+	}
+
+	/* For other cases, schedule work to write it "nicely" */
+	schedule_work(&cxt->work_write);
+}
 
 static void mtdoops_notify_add(struct mtd_info *mtd)
 {
@@ -296,7 +340,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 
 	do_div(mtdoops_pages, record_size);
 
-	if (cxt->name && !strcmp(mtd->name, cxt->name))
+	if (!strcmp(mtd->name, mtddev))
 		cxt->mtd_index = mtd->index;
 
 	if (mtd->index != cxt->mtd_index || cxt->mtd_index < 0)
@@ -327,6 +371,14 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		printk(KERN_ERR "Could not allocate page array\n");
 		return;
 	}
+	cxt->dump.dump = mtdoops_do_dump;
+	if (kmsg_dump_register(&cxt->dump) < 0) {
+		printk(KERN_ERR "Registering kmsg dumper failed\n");
+		vfree(cxt->oops_page_used);
+		cxt->oops_page_used = NULL;
+		return;
+	}
+
 	cxt->mtd = mtd;
 
 	cxt->oops_pages = (int)mtd->size / record_size;
@@ -343,116 +395,29 @@ 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 "Could not unregister kmsg_dumper??\n");
+
 	cxt->mtd = NULL;
 	flush_scheduled_work();
 }
 
-static void mtdoops_console_sync(void)
-{
-	struct mtdoops_context *cxt = &oops_cxt;
-	struct mtd_info *mtd = cxt->mtd;
-	unsigned long flags;
-
-	if (!cxt->ready || !mtd || cxt->writecount == 0)
-		return;
-
-	/*
-	 *  Once ready is 0 and we've held the lock no further writes to the
-	 *  buffer will happen
-	 */
-	spin_lock_irqsave(&cxt->writecount_lock, flags);
-	if (!cxt->ready) {
-		spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-		return;
-	}
-	cxt->ready = 0;
-	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-
-	if (mtd->panic_write && (in_interrupt() || panic_on_oops))
-		/* Interrupt context, we're going to panic so try and log */
-		mtdoops_write(cxt, 1);
-	else
-		schedule_work(&cxt->work_write);
-}
-
-static void
-mtdoops_console_write(struct console *co, const char *s, unsigned int count)
-{
-	struct mtdoops_context *cxt = co->data;
-	struct mtd_info *mtd = cxt->mtd;
-	unsigned long flags;
-
-	if (!oops_in_progress) {
-		mtdoops_console_sync();
-		return;
-	}
-
-	if (!cxt->ready || !mtd)
-		return;
-
-	/* Locking on writecount ensures sequential writes to the buffer */
-	spin_lock_irqsave(&cxt->writecount_lock, flags);
-
-	/* Check ready status didn't change whilst waiting for the lock */
-	if (!cxt->ready) {
-		spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-		return;
-	}
-
-	if (cxt->writecount == 0) {
-		u32 *stamp = cxt->oops_buf;
-		*stamp++ = cxt->nextcount;
-		*stamp = MTDOOPS_KERNMSG_MAGIC;
-		cxt->writecount = 8;
-	}
-
-	if (count + cxt->writecount > record_size)
-		count = record_size - cxt->writecount;
-
-	memcpy(cxt->oops_buf + cxt->writecount, s, count);
-	cxt->writecount += count;
-
-	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-
-	if (cxt->writecount == record_size)
-		mtdoops_console_sync();
-}
-
-static int __init mtdoops_console_setup(struct console *co, char *options)
-{
-	struct mtdoops_context *cxt = co->data;
-
-	if (cxt->mtd_index != -1 || cxt->name)
-		return -EBUSY;
-	if (options) {
-		cxt->name = kstrdup(options, GFP_KERNEL);
-		return 0;
-	}
-	if (co->index == -1)
-		return -EINVAL;
-
-	cxt->mtd_index = co->index;
-	return 0;
-}
 
 static struct mtd_notifier mtdoops_notifier = {
 	.add	= mtdoops_notify_add,
 	.remove	= mtdoops_notify_remove,
 };
 
-static struct console mtdoops_console = {
-	.name		= "ttyMTD",
-	.write		= mtdoops_console_write,
-	.setup		= mtdoops_console_setup,
-	.unblank	= mtdoops_console_sync,
-	.index		= -1,
-	.data		= &oops_cxt,
-};
-
-static int __init mtdoops_console_init(void)
+static int __init mtdoops_init(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
+	int mtd_index;
+	char *endp;
 
+	if (strlen(mtddev) == 0) {
+		printk(KERN_ERR "mtdoops: mtd device (mtddev=name/number) must be supplied\n");
+		return -EINVAL;
+	}
 	if ((record_size & 4095) != 0) {
 		printk(KERN_ERR "mtdoops: record_size must be a multiple of 4096\n");
 		return -EINVAL;
@@ -461,36 +426,39 @@ static int __init mtdoops_console_init(void)
 		printk(KERN_ERR "mtdoops: record_size must be over 4096 bytes\n");
 		return -EINVAL;
 	}
+
+	/* Setup the MTD device to use */
 	cxt->mtd_index = -1;
+	mtd_index = simple_strtoul(mtddev, &endp, 0);
+	if (endp != mtddev)
+		cxt->mtd_index = mtd_index;
+
 	cxt->oops_buf = vmalloc(record_size);
 	if (!cxt->oops_buf) {
 		printk(KERN_ERR "mtdoops: failed to allocate buffer workspace\n");
 		return -ENOMEM;
 	}
+	memset(cxt->oops_buf, 0xff, record_size);
 
-	spin_lock_init(&cxt->writecount_lock);
 	INIT_WORK(&cxt->work_erase, mtdoops_workfunc_erase);
 	INIT_WORK(&cxt->work_write, mtdoops_workfunc_write);
 
-	register_console(&mtdoops_console);
 	register_mtd_user(&mtdoops_notifier);
 	return 0;
 }
 
-static void __exit mtdoops_console_exit(void)
+static void __exit mtdoops_exit(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
 
 	unregister_mtd_user(&mtdoops_notifier);
-	unregister_console(&mtdoops_console);
-	kfree(cxt->name);
 	vfree(cxt->oops_buf);
 	vfree(cxt->oops_page_used);
 }
 
 
-subsys_initcall(mtdoops_console_init);
-module_exit(mtdoops_console_exit);
+module_init(mtdoops_init);
+module_exit(mtdoops_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* Re: [PATCH v12 1/4]: mtdoops: Keep track of used/unused mtdoops pages in an array
  2009-10-29 12:41   ` [PATCH v12 1/4]: mtdoops: Keep track of used/unused mtdoops pages in an array Simon Kagstrom
@ 2009-10-29 15:24     ` Artem Bityutskiy
  0 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-29 15:24 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: linux-mtd

On Thu, 2009-10-29 at 13:41 +0100, Simon Kagstrom wrote:
> This patch makes mtdoops keep track of used/unused pages in an array
> instead of scanning the flash after a write. The advantage with this
> approach is that it avoids calling mtd->read on a panic, which is not
> possible for all mtd drivers.
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>

Pushed this one to my tree, thanks.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v12 2/4]: mtdoops: Add a maximum MTD partition size
  2009-10-29 12:41   ` [PATCH v12 2/4]: mtdoops: Add a maximum MTD partition size Simon Kagstrom
@ 2009-10-29 15:27     ` Artem Bityutskiy
  2009-11-03  6:23     ` Artem Bityutskiy
  1 sibling, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-10-29 15:27 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: linux-mtd

On Thu, 2009-10-29 at 13:41 +0100, Simon Kagstrom wrote:
> A configurable maximum MTD partition size for mtdoops avoids mistakes
> where the user gives e.g., a rootfs partition to mtdoops (which will
> happily erase it).
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> ---
>  drivers/mtd/Kconfig   |   13 +++++++++++++
>  drivers/mtd/mtdoops.c |   11 +++++++----
>  2 files changed, 20 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
> index ecf90f5..9a69af8 100644
> --- a/drivers/mtd/Kconfig
> +++ b/drivers/mtd/Kconfig
> @@ -315,6 +315,19 @@ config MTD_OOPS
>  	  To use, add console=ttyMTDx to the kernel command line,
>  	  where x is the MTD device number to use.
>  
> +config MTD_OOPS_MAX_MTD_SIZE
> +	int "Maximum MTD oops partition size (kbytes)"
> +	default 4096
> +	range 8 1048576
> +	depends on MTD_OOPS
> +	help
> +	  This parameter sets the maximum MTD partition size for use with
> +	  MTD oops. The default value is used as a safeguard against using
> +	  e.g., a root filesystem partition as a MTDoops device (in which
> +	  case it will be erased).
> +
> +	  No need to change unless you have a very large MTDoops partition.
> +
>  source "drivers/mtd/chips/Kconfig"

Could we please just make it hard limited to something like 64MiB in the
driver itself. This configuration option is not really needed. There are
not many users of this driver, and I do not think any of them would ever
need a big partition for mtdoops, so there is not reason to make things
more complex than they are by introducing this configuration option.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v12 2/4]: mtdoops: Add a maximum MTD partition size
  2009-10-29 12:41   ` [PATCH v12 2/4]: mtdoops: Add a maximum MTD partition size Simon Kagstrom
  2009-10-29 15:27     ` Artem Bityutskiy
@ 2009-11-03  6:23     ` Artem Bityutskiy
  1 sibling, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-11-03  6:23 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: linux-mtd

On Thu, 2009-10-29 at 13:41 +0100, Simon Kagstrom wrote:
> A configurable maximum MTD partition size for mtdoops avoids mistakes
> where the user gives e.g., a rootfs partition to mtdoops (which will
> happily erase it).
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>

I've amended your patch and pushed the amended version to my tree.
Please, validate.

>From 9483bcb6b097ef3078e5a8798012e06e5156e54e Mon Sep 17 00:00:00 2001
From: Simon Kagstrom <simon.kagstrom@netinsight.net>
Date: Tue, 3 Nov 2009 08:08:41 +0200
Subject: mtd: mtdoops: limit the maximum mtd partition size

Make the maximum mtdoops partition size to be 32MiB. Indeed, it does
not make sense to use anything larger than that anyway. This limit
makes it possible to catch stupid mistakes where the user gives e.g.,
a rootfs partition to mtdoops (which will happily erase it).

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 drivers/mtd/mtdoops.c |   16 ++++++++++------
 1 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 06c5382..2493c08 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -33,6 +33,8 @@
 #include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
 
+/* Maximum MTD partition size, MiB */
+#define MTDOOPS_MAX_MTD_SIZE 32
 #define MTDOOPS_KERNMSG_MAGIC 0x5d005d00
 #define OOPS_PAGE_SIZE 4096
 
@@ -310,6 +312,12 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		return;
 	}
 
+	if (mtd->size > MTDOOPS_MAX_MTD_SIZE) {
+		printk(KERN_ERR "mtdoops: mtd%d is too large (limit is %d MiB)\n",
+		       mtd->index, MTDOOPS_MAX_MTD_SIZE);
+		return;
+	}
+
 	/* oops_page_used is a bit field */
 	cxt->oops_page_used = vmalloc(DIV_ROUND_UP(mtdoops_pages,
 			BITS_PER_LONG));
@@ -317,14 +325,10 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		printk(KERN_ERR "Could not allocate page array\n");
 		return;
 	}
-	cxt->mtd = mtd;
-	if (mtd->size > INT_MAX)
-		cxt->oops_pages = INT_MAX / OOPS_PAGE_SIZE;
-	else
-		cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE;
 
+	cxt->mtd = mtd;
+	cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE;
 	find_next_position(cxt);
-
 	printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index);
 }
 
-- 
1.6.2.5

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* Re: [PATCH v12 3/4]: mtdoops: Make page (record) size configurable
  2009-10-29 12:41   ` [PATCH v12 3/4]: mtdoops: Make page (record) size configurable Simon Kagstrom
@ 2009-11-03  6:23     ` Artem Bityutskiy
  2009-11-03  7:27       ` Simon Kagstrom
  0 siblings, 1 reply; 94+ messages in thread
From: Artem Bityutskiy @ 2009-11-03  6:23 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: linux-mtd

On Thu, 2009-10-29 at 13:41 +0100, Simon Kagstrom wrote:
> The main justification for this is to allow catching long messages
> during a panic, where the top part might otherwise be lost since moving
> to the next block can require a flash erase.
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
> ---
> ChangeLog:
>  * Rebased over "[PATCH v12 2/4]: mtdoops: Add a maximum MTD partition size"
> 
>  drivers/mtd/mtdoops.c |   75 ++++++++++++++++++++++++++++--------------------
>  1 files changed, 44 insertions(+), 31 deletions(-)

Pushed this one to my tree, on top of the previous patch which I
tweaked, thanks.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v12 3/4]: mtdoops: Make page (record) size configurable
  2009-11-03  6:23     ` Artem Bityutskiy
@ 2009-11-03  7:27       ` Simon Kagstrom
  2009-11-03  7:45         ` Artem Bityutskiy
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Kagstrom @ 2009-11-03  7:27 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd

On Tue, 03 Nov 2009 08:23:58 +0200
Artem Bityutskiy <dedekind1@gmail.com> wrote:

> On Thu, 2009-10-29 at 13:41 +0100, Simon Kagstrom wrote:
> > The main justification for this is to allow catching long messages
> > during a panic, where the top part might otherwise be lost since moving
> > to the next block can require a flash erase.
> > 
> > Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> > Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
> > ---
> > ChangeLog:
> >  * Rebased over "[PATCH v12 2/4]: mtdoops: Add a maximum MTD partition size"
> > 
> >  drivers/mtd/mtdoops.c |   75 ++++++++++++++++++++++++++++--------------------
> >  1 files changed, 44 insertions(+), 31 deletions(-)
> 
> Pushed this one to my tree, on top of the previous patch which I
> tweaked, thanks.

Thanks! I was going to send an updated patch in, but I've had some
other work to do lately. I'll send in a new version of the final patch
before the end of the day.


I noticed a small issue in your updated patch:

> +/* Maximum MTD partition size, MiB */
> +#define MTDOOPS_MAX_MTD_SIZE 32

> @@ -310,6 +312,12 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
>  		return;
>  	}
>  
> +	if (mtd->size > MTDOOPS_MAX_MTD_SIZE) {
> +		printk(KERN_ERR "mtdoops: mtd%d is too large (limit is %d MiB)\n",
> +		       mtd->index, MTDOOPS_MAX_MTD_SIZE);

mtd->size should be in bytes, right? So this will only check that it's
larger than 32 bytes, which most users will probably want ;-)

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v12 4/4]: mtdoops: refactor as a kmsg_dumper
  2009-10-29 12:41   ` [PATCH v12 4/4]: mtdoops: refactor as a kmsg_dumper Simon Kagstrom
@ 2009-11-03  7:29     ` Artem Bityutskiy
  2009-11-03 13:19       ` [PATCH v13 " Simon Kagstrom
  0 siblings, 1 reply; 94+ messages in thread
From: Artem Bityutskiy @ 2009-11-03  7:29 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: linux-mtd

On Thu, 2009-10-29 at 13:41 +0100, Simon Kagstrom wrote:
> The last messages which happens before a crash might contain interesting
> information about the crash. This patch reworks mtdoops using the
> kmsg_dumper support instead of a console, which simplifies the code and
> also includes the messages before the oops started.
> 
> On oops callbacks, the MTD device write is scheduled in a work queue (to
> be able to use the regular mtd->write call), while panics call
> mtd->panic_write directly. Thus, if panic_on_oops is set, the oops will
> be written out during the panic.
> 
> A parameter to specify which mtd device to use (number or name), as well
> as a flag, writable at runtime, to toggle wheter to dump oopses or only
> panics (since oopses can often be handled by regular syslog).
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
> ---
> ChangeLog:
>   * Rebased on top of "[PATCH v12 3/4]: mtdoops: Make page (record) size configurable"
> 
>  drivers/mtd/Kconfig   |    5 +-
>  drivers/mtd/mtdoops.c |  218 +++++++++++++++++++++----------------------------
>  2 files changed, 96 insertions(+), 127 deletions(-)
> 

... snip ...

> -static int __init mtdoops_console_init(void)
> +static int __init mtdoops_init(void)
>  {
>  	struct mtdoops_context *cxt = &oops_cxt;
> +	int mtd_index;
> +	char *endp;
>  
> +	if (strlen(mtddev) == 0) {
> +		printk(KERN_ERR "mtdoops: mtd device (mtddev=name/number) must be supplied\n");
> +		return -EINVAL;
> +	}
>  	if ((record_size & 4095) != 0) {
>  		printk(KERN_ERR "mtdoops: record_size must be a multiple of 4096\n");
>  		return -EINVAL;
> @@ -461,36 +426,39 @@ static int __init mtdoops_console_init(void)
>  		printk(KERN_ERR "mtdoops: record_size must be over 4096 bytes\n");
>  		return -EINVAL;
>  	}
> +
> +	/* Setup the MTD device to use */
>  	cxt->mtd_index = -1;
> +	mtd_index = simple_strtoul(mtddev, &endp, 0);
> +	if (endp != mtddev)
> +		cxt->mtd_index = mtd_index;

I think you should instead do

if (*endp == '\0')
	cxt->mtd_index = mtd_index;

instead. Otherwise the code will tread 'mtddev == 1xyz' as mtd1, which
is wrong.

And some sanity check to mtd_index would be nice, e.g., a check against
MAX_MTD_DEVICES.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v12 3/4]: mtdoops: Make page (record) size configurable
  2009-11-03  7:27       ` Simon Kagstrom
@ 2009-11-03  7:45         ` Artem Bityutskiy
  0 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-11-03  7:45 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: linux-mtd

On Tue, 2009-11-03 at 08:27 +0100, Simon Kagstrom wrote:
> On Tue, 03 Nov 2009 08:23:58 +0200
> Artem Bityutskiy <dedekind1@gmail.com> wrote:
> 
> > On Thu, 2009-10-29 at 13:41 +0100, Simon Kagstrom wrote:
> > > The main justification for this is to allow catching long messages
> > > during a panic, where the top part might otherwise be lost since moving
> > > to the next block can require a flash erase.
> > > 
> > > Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> > > Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
> > > ---
> > > ChangeLog:
> > >  * Rebased over "[PATCH v12 2/4]: mtdoops: Add a maximum MTD partition size"
> > > 
> > >  drivers/mtd/mtdoops.c |   75 ++++++++++++++++++++++++++++--------------------
> > >  1 files changed, 44 insertions(+), 31 deletions(-)
> > 
> > Pushed this one to my tree, on top of the previous patch which I
> > tweaked, thanks.
> 
> Thanks! I was going to send an updated patch in, but I've had some
> other work to do lately. I'll send in a new version of the final patch
> before the end of the day.
> 
> 
> I noticed a small issue in your updated patch:

Fixed, thanks. And made the limit to be 8MiB. Pushed to my tree and
inlined below.


>From 3d91aca8e7b4c1b6bfa44a941ff4341e73dc665c Mon Sep 17 00:00:00 2001
From: Simon Kagstrom <simon.kagstrom@netinsight.net>
Date: Tue, 3 Nov 2009 08:08:41 +0200
Subject: [PATCH] mtd: mtdoops: limit the maximum mtd partition size

Make the maximum mtdoops partition size to be 8MiB. Indeed, it does
not make sense to use anything larger than that anyway. This limit
makes it possible to catch stupid mistakes where the user gives e.g.,
a rootfs partition to mtdoops (which will happily erase it).

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 drivers/mtd/mtdoops.c |   17 +++++++++++------
 1 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 06c5382..b016eee 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -33,6 +33,9 @@
 #include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
 
+/* Maximum MTD partition size */
+#define MTDOOPS_MAX_MTD_SIZE (8 * 1024 * 1024)
+
 #define MTDOOPS_KERNMSG_MAGIC 0x5d005d00
 #define OOPS_PAGE_SIZE 4096
 
@@ -310,6 +313,12 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		return;
 	}
 
+	if (mtd->size > MTDOOPS_MAX_MTD_SIZE) {
+		printk(KERN_ERR "mtdoops: mtd%d is too large (limit is %d MiB)\n",
+		       mtd->index, MTDOOPS_MAX_MTD_SIZE / 1024 / 1024);
+		return;
+	}
+
 	/* oops_page_used is a bit field */
 	cxt->oops_page_used = vmalloc(DIV_ROUND_UP(mtdoops_pages,
 			BITS_PER_LONG));
@@ -317,14 +326,10 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		printk(KERN_ERR "Could not allocate page array\n");
 		return;
 	}
-	cxt->mtd = mtd;
-	if (mtd->size > INT_MAX)
-		cxt->oops_pages = INT_MAX / OOPS_PAGE_SIZE;
-	else
-		cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE;
 
+	cxt->mtd = mtd;
+	cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE;
 	find_next_position(cxt);
-
 	printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index);
 }
 
-- 
1.6.2.5


-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* [PATCH v13 4/4]: mtdoops: refactor as a kmsg_dumper
  2009-11-03  7:29     ` Artem Bityutskiy
@ 2009-11-03 13:19       ` Simon Kagstrom
  2009-11-10  9:55         ` Simon Kagstrom
                           ` (2 more replies)
  0 siblings, 3 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-11-03 13:19 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd

The last messages which happens before a crash might contain interesting
information about the crash. This patch reworks mtdoops using the
kmsg_dumper support instead of a console, which simplifies the code and
also includes the messages before the oops started.

On oops callbacks, the MTD device write is scheduled in a work queue (to
be able to use the regular mtd->write call), while panics call
mtd->panic_write directly. Thus, if panic_on_oops is set, the oops will
be written out during the panic.

A parameter to specify which mtd device to use (number or name), as well
as a flag, writable at runtime, to toggle wheter to dump oopses or only
panics (since oopses can often be handled by regular syslog).

Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
---
ChangeLog:
 v13:
	* Rebase against http://git.infradead.org/users/dedekind/l2-mtd-2.6.git
	* (Artem): Check simple_strtoul output to catch strings which only
	  start with numbers
	* (Artem): Check that the mtd_index does not exceed MAX_MTD_DEVICES

 drivers/mtd/mtdoops.c |  224 +++++++++++++++++++++----------------------------
 1 files changed, 97 insertions(+), 127 deletions(-)

diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 64772dc..731876a 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -29,21 +29,34 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/delay.h>
-#include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
+#include <linux/kmsg_dump.h>
 
 /* Maximum MTD partition size */
 #define MTDOOPS_MAX_MTD_SIZE (8 * 1024 * 1024)
 
 #define MTDOOPS_KERNMSG_MAGIC 0x5d005d00
+#define MTDOOPS_HEADER_SIZE   8
 
 static unsigned long record_size = 4096;
 module_param(record_size, ulong, 0400);
 MODULE_PARM_DESC(record_size,
 		"record size for MTD OOPS pages in bytes (default 4096)");
 
+static char mtddev[80];
+module_param_string(mtddev, mtddev, 80, 0400);
+MODULE_PARM_DESC(mtddev,
+		"name or index number of the MTD device to use");
+
+static int dump_oops = 1;
+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 struct mtdoops_context {
+	struct kmsg_dumper dump;
+
 	int mtd_index;
 	struct work_struct work_erase;
 	struct work_struct work_write;
@@ -52,14 +65,8 @@ static struct mtdoops_context {
 	int nextpage;
 	int nextcount;
 	unsigned long *oops_page_used;
-	char *name;
 
 	void *oops_buf;
-
-	/* writecount and disabling ready are spin lock protected */
-	spinlock_t writecount_lock;
-	int ready;
-	int writecount;
 } oops_cxt;
 
 static void mark_page_used(struct mtdoops_context *cxt, int page)
@@ -111,7 +118,7 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
 		remove_wait_queue(&wait_q, &wait);
 		printk(KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] on \"%s\" failed\n",
 		       (unsigned long long)erase.addr,
-		       (unsigned long long)erase.len, mtd->name);
+		       (unsigned long long)erase.len, mtddev);
 		return ret;
 	}
 
@@ -141,7 +148,6 @@ static void mtdoops_inc_counter(struct mtdoops_context *cxt)
 
 	printk(KERN_DEBUG "mtdoops: ready %d, %d (no erase)\n",
 	       cxt->nextpage, cxt->nextcount);
-	cxt->ready = 1;
 }
 
 /* Scheduled work - when we can't proceed without erasing a block */
@@ -190,7 +196,6 @@ badblock:
 	if (ret >= 0) {
 		printk(KERN_DEBUG "mtdoops: ready %d, %d\n",
 		       cxt->nextpage, cxt->nextcount);
-		cxt->ready = 1;
 		return;
 	}
 
@@ -208,11 +213,13 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 {
 	struct mtd_info *mtd = cxt->mtd;
 	size_t retlen;
+	u32 *hdr;
 	int ret;
 
-	if (cxt->writecount < record_size)
-		memset(cxt->oops_buf + cxt->writecount, 0xff,
-					record_size - cxt->writecount);
+	/* Add mtdoops header to the buffer */
+	hdr = cxt->oops_buf;
+	hdr[0] = cxt->nextcount;
+	hdr[1] = MTDOOPS_KERNMSG_MAGIC;
 
 	if (panic)
 		ret = mtd->panic_write(mtd, cxt->nextpage * record_size,
@@ -221,17 +228,15 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 		ret = mtd->write(mtd, cxt->nextpage * record_size,
 					record_size, &retlen, cxt->oops_buf);
 
-	cxt->writecount = 0;
-
 	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);
 	mark_page_used(cxt, cxt->nextpage);
+	memset(cxt->oops_buf, 0xff, record_size);
 
 	mtdoops_inc_counter(cxt);
 }
 
-
 static void mtdoops_workfunc_write(struct work_struct *work)
 {
 	struct mtdoops_context *cxt =
@@ -250,17 +255,18 @@ static void find_next_position(struct mtdoops_context *cxt)
 	for (page = 0; page < cxt->oops_pages; page++) {
 		/* Assume the page is used */
 		mark_page_used(cxt, page);
-		ret = mtd->read(mtd, page * record_size, 8, &retlen, (u_char *) &count[0]);
-		if (retlen != 8 || (ret < 0 && ret != -EUCLEAN)) {
-			printk(KERN_ERR "mtdoops: read failure at %ld (%td of 8 read), err %d\n",
-			       page * record_size, retlen, ret);
+		ret = mtd->read(mtd, page * record_size, MTDOOPS_HEADER_SIZE,
+				&retlen, (u_char *) &count[0]);
+		if (retlen != MTDOOPS_HEADER_SIZE ||
+				(ret < 0 && ret != -EUCLEAN)) {
+			printk(KERN_ERR "mtdoops: read failure at %ld (%td of %d read), err %d\n",
+			       page * record_size, retlen,
+			       MTDOOPS_HEADER_SIZE, ret);
 			continue;
 		}
 
 		if (count[0] == 0xffffffff && count[1] == 0xffffffff)
 			mark_page_unused(cxt, page);
-		if (count[1] != MTDOOPS_KERNMSG_MAGIC)
-			continue;
 		if (count[0] == 0xffffffff)
 			continue;
 		if (maxcount == 0xffffffff) {
@@ -291,6 +297,42 @@ 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)
+{
+	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;
+
+	/* 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;
+
+	memcpy(dst, s1 + s1_start, l1_cpy);
+	memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
+
+	/* Panics must be written immediately */
+	if (reason == KMSG_DUMP_PANIC) {
+		if (!cxt->mtd->panic_write)
+			printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n");
+		else
+			mtdoops_write(cxt, 1);
+		return;
+	}
+
+	/* For other cases, schedule work to write it "nicely" */
+	schedule_work(&cxt->work_write);
+}
 
 static void mtdoops_notify_add(struct mtd_info *mtd)
 {
@@ -299,7 +341,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 
 	do_div(mtdoops_pages, record_size);
 
-	if (cxt->name && !strcmp(mtd->name, cxt->name))
+	if (!strcmp(mtd->name, mtddev))
 		cxt->mtd_index = mtd->index;
 
 	if (mtd->index != cxt->mtd_index || cxt->mtd_index < 0)
@@ -330,6 +372,13 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		printk(KERN_ERR "Could not allocate page array\n");
 		return;
 	}
+	cxt->dump.dump = mtdoops_do_dump;
+	if (kmsg_dump_register(&cxt->dump) < 0) {
+		printk(KERN_ERR "Registering kmsg dumper failed\n");
+		vfree(cxt->oops_page_used);
+		cxt->oops_page_used = NULL;
+		return;
+	}
 
 	cxt->mtd = mtd;
 	cxt->oops_pages = (int)mtd->size / record_size;
@@ -344,116 +393,29 @@ 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 "Could not unregister kmsg_dumper??\n");
+
 	cxt->mtd = NULL;
 	flush_scheduled_work();
 }
 
-static void mtdoops_console_sync(void)
-{
-	struct mtdoops_context *cxt = &oops_cxt;
-	struct mtd_info *mtd = cxt->mtd;
-	unsigned long flags;
-
-	if (!cxt->ready || !mtd || cxt->writecount == 0)
-		return;
-
-	/*
-	 *  Once ready is 0 and we've held the lock no further writes to the
-	 *  buffer will happen
-	 */
-	spin_lock_irqsave(&cxt->writecount_lock, flags);
-	if (!cxt->ready) {
-		spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-		return;
-	}
-	cxt->ready = 0;
-	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-
-	if (mtd->panic_write && in_interrupt())
-		/* Interrupt context, we're going to panic so try and log */
-		mtdoops_write(cxt, 1);
-	else
-		schedule_work(&cxt->work_write);
-}
-
-static void
-mtdoops_console_write(struct console *co, const char *s, unsigned int count)
-{
-	struct mtdoops_context *cxt = co->data;
-	struct mtd_info *mtd = cxt->mtd;
-	unsigned long flags;
-
-	if (!oops_in_progress) {
-		mtdoops_console_sync();
-		return;
-	}
-
-	if (!cxt->ready || !mtd)
-		return;
-
-	/* Locking on writecount ensures sequential writes to the buffer */
-	spin_lock_irqsave(&cxt->writecount_lock, flags);
-
-	/* Check ready status didn't change whilst waiting for the lock */
-	if (!cxt->ready) {
-		spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-		return;
-	}
-
-	if (cxt->writecount == 0) {
-		u32 *stamp = cxt->oops_buf;
-		*stamp++ = cxt->nextcount;
-		*stamp = MTDOOPS_KERNMSG_MAGIC;
-		cxt->writecount = 8;
-	}
-
-	if (count + cxt->writecount > record_size)
-		count = record_size - cxt->writecount;
-
-	memcpy(cxt->oops_buf + cxt->writecount, s, count);
-	cxt->writecount += count;
-
-	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
-
-	if (cxt->writecount == record_size)
-		mtdoops_console_sync();
-}
-
-static int __init mtdoops_console_setup(struct console *co, char *options)
-{
-	struct mtdoops_context *cxt = co->data;
-
-	if (cxt->mtd_index != -1 || cxt->name)
-		return -EBUSY;
-	if (options) {
-		cxt->name = kstrdup(options, GFP_KERNEL);
-		return 0;
-	}
-	if (co->index == -1)
-		return -EINVAL;
-
-	cxt->mtd_index = co->index;
-	return 0;
-}
 
 static struct mtd_notifier mtdoops_notifier = {
 	.add	= mtdoops_notify_add,
 	.remove	= mtdoops_notify_remove,
 };
 
-static struct console mtdoops_console = {
-	.name		= "ttyMTD",
-	.write		= mtdoops_console_write,
-	.setup		= mtdoops_console_setup,
-	.unblank	= mtdoops_console_sync,
-	.index		= -1,
-	.data		= &oops_cxt,
-};
-
-static int __init mtdoops_console_init(void)
+static int __init mtdoops_init(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
+	int mtd_index;
+	char *endp;
 
+	if (strlen(mtddev) == 0) {
+		printk(KERN_ERR "mtdoops: mtd device (mtddev=name/number) must be supplied\n");
+		return -EINVAL;
+	}
 	if ((record_size & 4095) != 0) {
 		printk(KERN_ERR "mtdoops: record_size must be a multiple of 4096\n");
 		return -EINVAL;
@@ -462,36 +424,44 @@ static int __init mtdoops_console_init(void)
 		printk(KERN_ERR "mtdoops: record_size must be over 4096 bytes\n");
 		return -EINVAL;
 	}
+
+	/* Setup the MTD device to use */
 	cxt->mtd_index = -1;
+	mtd_index = simple_strtoul(mtddev, &endp, 0);
+	if (*endp == '\0')
+		cxt->mtd_index = mtd_index;
+	if (cxt->mtd_index > MAX_MTD_DEVICES) {
+		printk(KERN_ERR "mtdoops: invalid mtd device number (%u) given\n",
+				mtd_index);
+		return -EINVAL;
+	}
+
 	cxt->oops_buf = vmalloc(record_size);
 	if (!cxt->oops_buf) {
 		printk(KERN_ERR "mtdoops: failed to allocate buffer workspace\n");
 		return -ENOMEM;
 	}
+	memset(cxt->oops_buf, 0xff, record_size);
 
-	spin_lock_init(&cxt->writecount_lock);
 	INIT_WORK(&cxt->work_erase, mtdoops_workfunc_erase);
 	INIT_WORK(&cxt->work_write, mtdoops_workfunc_write);
 
-	register_console(&mtdoops_console);
 	register_mtd_user(&mtdoops_notifier);
 	return 0;
 }
 
-static void __exit mtdoops_console_exit(void)
+static void __exit mtdoops_exit(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
 
 	unregister_mtd_user(&mtdoops_notifier);
-	unregister_console(&mtdoops_console);
-	kfree(cxt->name);
 	vfree(cxt->oops_buf);
 	vfree(cxt->oops_page_used);
 }
 
 
-subsys_initcall(mtdoops_console_init);
-module_exit(mtdoops_console_exit);
+module_init(mtdoops_init);
+module_exit(mtdoops_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* Re: [PATCH v13 4/4]: mtdoops: refactor as a kmsg_dumper
  2009-11-03 13:19       ` [PATCH v13 " Simon Kagstrom
@ 2009-11-10  9:55         ` Simon Kagstrom
  2009-11-10 11:53           ` Artem Bityutskiy
  2009-11-10 16:04         ` Artem Bityutskiy
  2009-11-10 16:11         ` Artem Bityutskiy
  2 siblings, 1 reply; 94+ messages in thread
From: Simon Kagstrom @ 2009-11-10  9:55 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd

Hi Artem,

On Tue, 3 Nov 2009 14:19:03 +0100
Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:

> The last messages which happens before a crash might contain interesting
> information about the crash. [...]
> ChangeLog:
>  v13:
> 	* Rebase against http://git.infradead.org/users/dedekind/l2-mtd-2.6.git
> 	* (Artem): Check simple_strtoul output to catch strings which only
> 	  start with numbers
> 	* (Artem): Check that the mtd_index does not exceed MAX_MTD_DEVICES

Are there any more issues which I should fix for this patch to get it
to an acceptable state?

Thanks,
// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v13 4/4]: mtdoops: refactor as a kmsg_dumper
  2009-11-10  9:55         ` Simon Kagstrom
@ 2009-11-10 11:53           ` Artem Bityutskiy
  2009-11-10 11:58             ` Simon Kagstrom
  0 siblings, 1 reply; 94+ messages in thread
From: Artem Bityutskiy @ 2009-11-10 11:53 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: linux-mtd

On Tue, 2009-11-10 at 10:55 +0100, Simon Kagstrom wrote:
> Hi Artem,
> 
> On Tue, 3 Nov 2009 14:19:03 +0100
> Simon Kagstrom <simon.kagstrom@netinsight.net> wrote:
> 
> > The last messages which happens before a crash might contain interesting
> > information about the crash. [...]
> > ChangeLog:
> >  v13:
> > 	* Rebase against http://git.infradead.org/users/dedekind/l2-mtd-2.6.git
> > 	* (Artem): Check simple_strtoul output to catch strings which only
> > 	  start with numbers
> > 	* (Artem): Check that the mtd_index does not exceed MAX_MTD_DEVICES
> 
> Are there any more issues which I should fix for this patch to get it
> to an acceptable state?

Sorry Simon, I just do not have enough time ATM. But I will look at this
ASAP. It is in my TODO queue.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v13 4/4]: mtdoops: refactor as a kmsg_dumper
  2009-11-10 11:53           ` Artem Bityutskiy
@ 2009-11-10 11:58             ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2009-11-10 11:58 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd

On Tue, 10 Nov 2009 13:53:41 +0200
Artem Bityutskiy <dedekind1@gmail.com> wrote:

> > Are there any more issues which I should fix for this patch to get it
> > to an acceptable state?
> 
> Sorry Simon, I just do not have enough time ATM. But I will look at this
> ASAP. It is in my TODO queue.

No hurry, I just thought it might have slipped into the holes between
the floor boards.

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v13 4/4]: mtdoops: refactor as a kmsg_dumper
  2009-11-03 13:19       ` [PATCH v13 " Simon Kagstrom
  2009-11-10  9:55         ` Simon Kagstrom
@ 2009-11-10 16:04         ` Artem Bityutskiy
  2009-11-10 16:11         ` Artem Bityutskiy
  2 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-11-10 16:04 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: linux-mtd

On Tue, 2009-11-03 at 14:19 +0100, Simon Kagstrom wrote:
> The last messages which happens before a crash might contain interesting
> information about the crash. This patch reworks mtdoops using the
> kmsg_dumper support instead of a console, which simplifies the code and
> also includes the messages before the oops started.
> 
> On oops callbacks, the MTD device write is scheduled in a work queue (to
> be able to use the regular mtd->write call), while panics call
> mtd->panic_write directly. Thus, if panic_on_oops is set, the oops will
> be written out during the panic.
> 
> A parameter to specify which mtd device to use (number or name), as well
> as a flag, writable at runtime, to toggle wheter to dump oopses or only
> panics (since oopses can often be handled by regular syslog).
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>

Pushed to my l2-mtd-2.6 tree with the following amendments on top,
please, review:

diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 731876a..a714ec4 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -337,9 +337,8 @@ static void mtdoops_do_dump(struct kmsg_dumper *dumper,
 static void mtdoops_notify_add(struct mtd_info *mtd)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
-	u64 mtdoops_pages = mtd->size;
-
-	do_div(mtdoops_pages, record_size);
+	u64 mtdoops_pages = div_u64(mtd->size, record_size);
+	int err;
 
 	if (!strcmp(mtd->name, mtddev))
 		cxt->mtd_index = mtd->index;
@@ -352,13 +351,11 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		       mtd->index);
 		return;
 	}
-
 	if (mtd->erasesize < record_size) {
 		printk(KERN_ERR "mtdoops: eraseblock size of MTD partition %d too small\n",
 		       mtd->index);
 		return;
 	}
-
 	if (mtd->size > MTDOOPS_MAX_MTD_SIZE) {
 		printk(KERN_ERR "mtdoops: mtd%d is too large (limit is %d MiB)\n",
 		       mtd->index, MTDOOPS_MAX_MTD_SIZE / 1024 / 1024);
@@ -369,12 +366,14 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 	cxt->oops_page_used = vmalloc(DIV_ROUND_UP(mtdoops_pages,
 			BITS_PER_LONG));
 	if (!cxt->oops_page_used) {
-		printk(KERN_ERR "Could not allocate page array\n");
+		printk(KERN_ERR "mtdoops: could not allocate page array\n");
 		return;
 	}
+
 	cxt->dump.dump = mtdoops_do_dump;
-	if (kmsg_dump_register(&cxt->dump) < 0) {
-		printk(KERN_ERR "Registering kmsg dumper failed\n");
+	err = kmsg_dump_register(&cxt->dump);
+	if (err) {
+		printk(KERN_ERR "mtdoops: registering kmsg dumper failed, error %d\n", err);
 		vfree(cxt->oops_page_used);
 		cxt->oops_page_used = NULL;
 		return;
@@ -394,7 +393,7 @@ static void mtdoops_notify_remove(struct mtd_info *mtd)
 		return;
 
 	if (kmsg_dump_unregister(&cxt->dump) < 0)
-		printk(KERN_WARNING "Could not unregister kmsg_dumper??\n");
+		printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n");
 
 	cxt->mtd = NULL;
 	flush_scheduled_work();

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply related	[flat|nested] 94+ messages in thread

* Re: [PATCH v13 4/4]: mtdoops: refactor as a kmsg_dumper
  2009-11-03 13:19       ` [PATCH v13 " Simon Kagstrom
  2009-11-10  9:55         ` Simon Kagstrom
  2009-11-10 16:04         ` Artem Bityutskiy
@ 2009-11-10 16:11         ` Artem Bityutskiy
  2009-11-11  9:46           ` Simon Kagstrom
  2 siblings, 1 reply; 94+ messages in thread
From: Artem Bityutskiy @ 2009-11-10 16:11 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: linux-mtd

On Tue, 2009-11-03 at 14:19 +0100, Simon Kagstrom wrote:
> The last messages which happens before a crash might contain interesting
> information about the crash. This patch reworks mtdoops using the
> kmsg_dumper support instead of a console, which simplifies the code and
> also includes the messages before the oops started.
> 
> On oops callbacks, the MTD device write is scheduled in a work queue (to
> be able to use the regular mtd->write call), while panics call
> mtd->panic_write directly. Thus, if panic_on_oops is set, the oops will
> be written out during the panic.
> 
> A parameter to specify which mtd device to use (number or name), as well
> as a flag, writable at runtime, to toggle wheter to dump oopses or only
> panics (since oopses can often be handled by regular syslog).
> 
> Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
> Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>

Do we really need this notifiers? Would not it be better to open mtd
device straight in the module_init function instead?

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v13 4/4]: mtdoops: refactor as a kmsg_dumper
  2009-11-10 16:11         ` Artem Bityutskiy
@ 2009-11-11  9:46           ` Simon Kagstrom
  2009-11-11 10:29             ` Artem Bityutskiy
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Kagstrom @ 2009-11-11  9:46 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd

On Tue, 10 Nov 2009 18:11:33 +0200

> Do we really need this notifiers? Would not it be better to open mtd
> device straight in the module_init function instead?

If the mtdoops driver is built into the kernel, module_init might be
(and I believe will be) called before the MTD partitions have been
created. With the MTD notifiers, this problem is worked around.

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v13 4/4]: mtdoops: refactor as a kmsg_dumper
  2009-11-11  9:46           ` Simon Kagstrom
@ 2009-11-11 10:29             ` Artem Bityutskiy
  2009-11-11 11:27               ` Simon Kagstrom
  0 siblings, 1 reply; 94+ messages in thread
From: Artem Bityutskiy @ 2009-11-11 10:29 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: linux-mtd

On Wed, 2009-11-11 at 10:46 +0100, Simon Kagstrom wrote:
> On Tue, 10 Nov 2009 18:11:33 +0200
> 
> > Do we really need this notifiers? Would not it be better to open mtd
> > device straight in the module_init function instead?
> 
> If the mtdoops driver is built into the kernel, module_init might be
> (and I believe will be) called before the MTD partitions have been
> created. With the MTD notifiers, this problem is worked around.

But this is why we have late_initcall(), which we can use instead of
module_init().

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v13 4/4]: mtdoops: refactor as a kmsg_dumper
  2009-11-11 10:29             ` Artem Bityutskiy
@ 2009-11-11 11:27               ` Simon Kagstrom
  2009-11-11 11:34                 ` Artem Bityutskiy
  0 siblings, 1 reply; 94+ messages in thread
From: Simon Kagstrom @ 2009-11-11 11:27 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd

On Wed, 11 Nov 2009 12:29:42 +0200
Artem Bityutskiy <dedekind1@gmail.com> wrote:

> On Wed, 2009-11-11 at 10:46 +0100, Simon Kagstrom wrote:
> > On Tue, 10 Nov 2009 18:11:33 +0200
> > 
> > > Do we really need this notifiers? Would not it be better to open mtd
> > > device straight in the module_init function instead?
> > 
> > If the mtdoops driver is built into the kernel, module_init might be
> > (and I believe will be) called before the MTD partitions have been
> > created. With the MTD notifiers, this problem is worked around.
> 
> But this is why we have late_initcall(), which we can use instead of
> module_init().

OK, makes sense (you learn something new every day!). But I still have
one, perhaps artificial, use-case for keeping it as-is: MTD devices
might show up later if they are loaded as modules. In my case I use
phram as a module, and if I were to use that with MTDoops in the
kernel, I still need the notifiers.

But loading mtdoops after phram would also work obviously.

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v13 4/4]: mtdoops: refactor as a kmsg_dumper
  2009-11-11 11:27               ` Simon Kagstrom
@ 2009-11-11 11:34                 ` Artem Bityutskiy
  0 siblings, 0 replies; 94+ messages in thread
From: Artem Bityutskiy @ 2009-11-11 11:34 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: linux-mtd

On Wed, 2009-11-11 at 12:27 +0100, Simon Kagstrom wrote:
> On Wed, 11 Nov 2009 12:29:42 +0200
> Artem Bityutskiy <dedekind1@gmail.com> wrote:
> 
> > On Wed, 2009-11-11 at 10:46 +0100, Simon Kagstrom wrote:
> > > On Tue, 10 Nov 2009 18:11:33 +0200
> > > 
> > > > Do we really need this notifiers? Would not it be better to open mtd
> > > > device straight in the module_init function instead?
> > > 
> > > If the mtdoops driver is built into the kernel, module_init might be
> > > (and I believe will be) called before the MTD partitions have been
> > > created. With the MTD notifiers, this problem is worked around.
> > 
> > But this is why we have late_initcall(), which we can use instead of
> > module_init().
> 
> OK, makes sense (you learn something new every day!). But I still have
> one, perhaps artificial, use-case for keeping it as-is: MTD devices
> might show up later if they are loaded as modules. In my case I use
> phram as a module, and if I were to use that with MTDoops in the
> kernel, I still need the notifiers.

I do not insist at all, but I thought this is just error prone way. You
load mtdoops, which then lurks, and when appropriate MTD device appears,
it grabs it. But what if I just forgot to unload mtdoops and it grabs my
mtd1 device and formats it?

Besides, currently mtdoops may fail to grab the mtd device for some
reasons (an error), and all you have is an error message. If you do not
notice it, you may happily think you have working mtdoops, while you do
not.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v7 5/5]: mtdoops: refactor as a kmsg_dumper
  2009-10-15  7:48 ` [PATCH v7 5/5]: mtdoops: refactor as a kmsg_dumper Simon Kagstrom
  2009-10-15 14:10   ` [PATCH v8 " Simon Kagstrom
  2009-10-23  4:32   ` [PATCH v7 " Artem Bityutskiy
@ 2010-01-06 14:33   ` David Woodhouse
  2010-01-07  6:47     ` Simon Kagstrom
  2 siblings, 1 reply; 94+ messages in thread
From: David Woodhouse @ 2010-01-06 14:33 UTC (permalink / raw)
  To: Simon Kagstrom; +Cc: linux-mtd, Artem Bityutskiy

Hmmm.

On Thu, 2009-10-15 at 09:48 +0200, Simon Kagstrom wrote:
> +	/* Panics must be written immediately */
> +	if (reason == kmsg_dump_panic) {
> +		if (!cxt->mtd->panic_write)
> +			printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n");
> +		else
> +			mtdoops_write(cxt, 1);
> +		return;
> +	}
> +

...replaces...

> -	if (mtd->panic_write && (in_interrupt() || panic_on_oops))
> -		/* Interrupt context, we're going to panic so try and log */
> -		mtdoops_write(cxt, 1);
> -	else
> -		schedule_work(&cxt->work_write);
> -}

So in the case where the device driver doesn't provide a ->panic_oops()
function, we now don't even bother with a best-effort attempt to dump;
we just give up.

Would there be any harm in scheduling the work_write function _anyway_,
just in case it manages to run?

The bug report at http://bugzilla.kernel.org/show_bug.cgi?id=14102 seems
to be suggesting that sometimes it _did_ manage to work, with a bit of
luck and a following wind.

Also, it looks like in the (in_interrupt() || panic_on_oops) case we end
up calling kmsg_dump(KMSG_DUMP_OOPS) from oops_exit(), almost
immediately followed by kmsg_dump(KMSG_DUMP_PANIC). Is that going to do
the right thing?

-- 
David Woodhouse                            Open Source Technology Centre
David.Woodhouse@intel.com                              Intel Corporation

^ permalink raw reply	[flat|nested] 94+ messages in thread

* Re: [PATCH v7 5/5]: mtdoops: refactor as a kmsg_dumper
  2010-01-06 14:33   ` David Woodhouse
@ 2010-01-07  6:47     ` Simon Kagstrom
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Kagstrom @ 2010-01-07  6:47 UTC (permalink / raw)
  To: David Woodhouse; +Cc: linux-mtd, Artem Bityutskiy

On Wed, 06 Jan 2010 14:33:16 +0000
David Woodhouse <dwmw2@infradead.org> wrote:

> > +	/* Panics must be written immediately */
> > +	if (reason == kmsg_dump_panic) {
> > +		if (!cxt->mtd->panic_write)
> > +			printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n");
> > +		else
> > +			mtdoops_write(cxt, 1);
> > +		return;
> 
> Would there be any harm in scheduling the work_write function _anyway_,
> just in case it manages to run?
> 
> The bug report at http://bugzilla.kernel.org/show_bug.cgi?id=14102 seems
> to be suggesting that sometimes it _did_ manage to work, with a bit of
> luck and a following wind.

In my tests, I never got it to write out anything when using scheduled
work on panics. I did the tests on a uniprocessor though, maybe that
could be a reason.

But you are right, probably it doesn't hurt anyway. 

> Also, it looks like in the (in_interrupt() || panic_on_oops) case we end
> up calling kmsg_dump(KMSG_DUMP_OOPS) from oops_exit(), almost
> immediately followed by kmsg_dump(KMSG_DUMP_PANIC). Is that going to do
> the right thing?

Well, since I never got it to dump anything with the work queue, the
dump will be done when KMSG_DUMP_PANIC is called. The work queue never
gets to run, so I never saw double dumps with this approach.

Anyway, perhaps one could do a cancel_work() when running the panic
handler to avoid situations when both are written (since it apparently
is possible as above).

// Simon

^ permalink raw reply	[flat|nested] 94+ messages in thread

end of thread, other threads:[~2010-01-07  6:48 UTC | newest]

Thread overview: 94+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-10-15  7:40 [PATCH v7 0/5]: mtdoops: fixes and improvements Simon Kagstrom
2009-10-15  7:47 ` [PATCH v7 1/5]: mtdoops: avoid erasing already empty areas Simon Kagstrom
2009-10-23  3:57   ` Artem Bityutskiy
2009-10-15  7:47 ` [PATCH v7 2/5]: mtdoops: Keep track of used/unused mtdoops pages in an array Simon Kagstrom
2009-10-23  4:08   ` Artem Bityutskiy
2009-10-15  7:47 ` [PATCH v7 3/5]: mtdoops: Make page (record) size configurable Simon Kagstrom
2009-10-23  4:13   ` Artem Bityutskiy
2009-10-23  6:58     ` Simon Kagstrom
2009-10-15  7:48 ` [PATCH v7 4/5]: core: Add kernel message dumper to call on oopses and panics Simon Kagstrom
2009-10-15  7:48   ` Simon Kagstrom
2009-10-15  9:31   ` Ingo Molnar
2009-10-15  9:31     ` Ingo Molnar
2009-10-15 14:10     ` [PATCH v8 4/5] " Simon Kagstrom
2009-10-15 14:10       ` Simon Kagstrom
2009-10-15 15:46       ` Ingo Molnar
2009-10-15 15:46         ` Ingo Molnar
2009-10-16  7:46         ` [PATCH v9 " Simon Kagstrom
2009-10-16  7:46           ` Simon Kagstrom
2009-10-16  8:09           ` Ingo Molnar
2009-10-16  8:09             ` Ingo Molnar
2009-10-16  8:24             ` Artem Bityutskiy
2009-10-16  8:24               ` Artem Bityutskiy
2009-10-16  9:25               ` [PATCH v10 " Simon Kagstrom
2009-10-16  9:25                 ` Simon Kagstrom
2009-10-16 10:10                 ` Ingo Molnar
2009-10-16 10:10                   ` Ingo Molnar
2009-10-16 11:00                   ` Artem Bityutskiy
2009-10-16 11:00                     ` Artem Bityutskiy
2009-10-16 12:57                     ` Ingo Molnar
2009-10-16 12:57                       ` Ingo Molnar
2009-10-16 12:09                   ` [PATCH v11 " Simon Kagstrom
2009-10-16 12:09                     ` Simon Kagstrom
2009-10-19 11:48                     ` Artem Bityutskiy
2009-10-19 11:48                       ` Artem Bityutskiy
2009-10-19 12:50                       ` Ingo Molnar
2009-10-19 12:50                         ` Ingo Molnar
2009-10-21 23:33                         ` Linus Torvalds
2009-10-21 23:33                           ` Linus Torvalds
2009-10-22  6:25                           ` Simon Kagstrom
2009-10-22  6:25                             ` Simon Kagstrom
2009-10-22  6:36                             ` Artem Bityutskiy
2009-10-22  6:36                               ` Artem Bityutskiy
2009-10-22  6:42                               ` Simon Kagstrom
2009-10-22  8:52                                 ` Artem Bityutskiy
2009-10-22  8:58                                   ` Simon Kagstrom
2009-10-23  7:22                               ` Ingo Molnar
2009-10-23  7:22                                 ` Ingo Molnar
2009-10-23 15:53                             ` Shargorodsky Atal (EXT-Teleca/Helsinki)
2009-10-23 15:53                               ` Shargorodsky Atal (EXT-Teleca/Helsinki)
2009-10-24 17:05                               ` Artem Bityutskiy
2009-10-24 17:05                                 ` Artem Bityutskiy
2009-10-26 10:40                                 ` Shargorodsky Atal (EXT-Teleca/Helsinki)
2009-10-26 10:40                                   ` Shargorodsky Atal (EXT-Teleca/Helsinki)
2009-10-26  7:41                               ` Simon Kagstrom
2009-10-26  7:41                                 ` Simon Kagstrom
2009-10-26 10:36                                 ` Shargorodsky Atal (EXT-Teleca/Helsinki)
2009-10-26 10:36                                   ` Shargorodsky Atal (EXT-Teleca/Helsinki)
2009-10-26 11:53                                   ` Simon Kagstrom
2009-10-26 11:53                                     ` Simon Kagstrom
2009-10-26 15:13                                     ` Shargorodsky Atal (EXT-Teleca/Helsinki)
2009-10-26 15:13                                       ` Shargorodsky Atal (EXT-Teleca/Helsinki)
2009-10-26 15:37                                       ` Simon Kagstrom
2009-10-26 15:37                                         ` Simon Kagstrom
2009-10-16 11:25                 ` [PATCH v10 " Aaro Koskinen
2009-10-16 11:25                   ` Aaro Koskinen
2009-10-15  7:48 ` [PATCH v7 5/5]: mtdoops: refactor as a kmsg_dumper Simon Kagstrom
2009-10-15 14:10   ` [PATCH v8 " Simon Kagstrom
2009-10-16  7:46     ` [PATCH v9 " Simon Kagstrom
2009-10-23  4:32   ` [PATCH v7 " Artem Bityutskiy
2009-10-23  6:34     ` Simon Kagstrom
2010-01-06 14:33   ` David Woodhouse
2010-01-07  6:47     ` Simon Kagstrom
2009-10-29 12:35 ` [PATCH v12 0/4]: mtdoops: fixes and improvements Simon Kagstrom
2009-10-29 12:41   ` [PATCH v12 1/4]: mtdoops: Keep track of used/unused mtdoops pages in an array Simon Kagstrom
2009-10-29 15:24     ` Artem Bityutskiy
2009-10-29 12:41   ` [PATCH v12 2/4]: mtdoops: Add a maximum MTD partition size Simon Kagstrom
2009-10-29 15:27     ` Artem Bityutskiy
2009-11-03  6:23     ` Artem Bityutskiy
2009-10-29 12:41   ` [PATCH v12 3/4]: mtdoops: Make page (record) size configurable Simon Kagstrom
2009-11-03  6:23     ` Artem Bityutskiy
2009-11-03  7:27       ` Simon Kagstrom
2009-11-03  7:45         ` Artem Bityutskiy
2009-10-29 12:41   ` [PATCH v12 4/4]: mtdoops: refactor as a kmsg_dumper Simon Kagstrom
2009-11-03  7:29     ` Artem Bityutskiy
2009-11-03 13:19       ` [PATCH v13 " Simon Kagstrom
2009-11-10  9:55         ` Simon Kagstrom
2009-11-10 11:53           ` Artem Bityutskiy
2009-11-10 11:58             ` Simon Kagstrom
2009-11-10 16:04         ` Artem Bityutskiy
2009-11-10 16:11         ` Artem Bityutskiy
2009-11-11  9:46           ` Simon Kagstrom
2009-11-11 10:29             ` Artem Bityutskiy
2009-11-11 11:27               ` Simon Kagstrom
2009-11-11 11:34                 ` Artem Bityutskiy

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.