linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] pstore: add interface for dumpers and add task list dumper
@ 2012-10-15 11:40 dragos.tatulea
  2012-10-15 11:40 ` [PATCH 1/8] pstore: add flags dragos.tatulea
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: dragos.tatulea @ 2012-10-15 11:40 UTC (permalink / raw)
  To: cbouatmailru, linux-kernel
  Cc: adrian.hunter, octavian.purdila, Dragos Tatulea

From: Dragos Tatulea <dragos.tatulea@intel.com>

This patchset adds an interface for registering various clients (dumpers)
that can save info into pstore at crash time.

Such a dumper is added which does task list dumping.

Adrian Hunter (4):
  pstore: add flags
  pstore: add debugfs support for causing dumps and panics
  pstore: add support for external writers
  pstore: do not run timer while pstore is not mounted

Dragos Tatulea (4):
  pstore: allow storing different type id's in ram backend
  pstore: add task list dumper
  pstore: make sure pstore_write exists on flush error
  pstore: max out console log level during sysfs dump switch

 fs/pstore/Kconfig      |   12 ++++
 fs/pstore/Makefile     |    1 +
 fs/pstore/dump_tasks.c |  107 ++++++++++++++++++++++++++++
 fs/pstore/inode.c      |    6 ++
 fs/pstore/internal.h   |    2 +
 fs/pstore/platform.c   |  184 ++++++++++++++++++++++++++++++++++++++++++++++--
 fs/pstore/ram.c        |   18 +++--
 include/linux/pstore.h |   46 ++++++++++--
 8 files changed, 356 insertions(+), 20 deletions(-)
 create mode 100644 fs/pstore/dump_tasks.c

-- 
1.7.9.5


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

* [PATCH 1/8] pstore: add flags
  2012-10-15 11:40 [PATCH 0/8] pstore: add interface for dumpers and add task list dumper dragos.tatulea
@ 2012-10-15 11:40 ` dragos.tatulea
  2012-10-15 11:40 ` [PATCH 2/8] pstore: add debugfs support for causing dumps and panics dragos.tatulea
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: dragos.tatulea @ 2012-10-15 11:40 UTC (permalink / raw)
  To: cbouatmailru, linux-kernel; +Cc: adrian.hunter, octavian.purdila

From: Adrian Hunter <adrian.hunter@intel.com>

Let the back end tweak pstore behaviour.  Flags added are:

	PSTORE_NO_HEADINGS

		Omit pstore heading lines from dumped data

	PSTORE_MAX_KMSG_BYTES

		Default kmsg_bytes to ULONG_MAX

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 fs/pstore/platform.c   |    9 ++++++++-
 include/linux/pstore.h |    4 ++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index a40da07..c4ea778 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -128,7 +128,11 @@ static void pstore_dump(struct kmsg_dumper *dumper,
 		size_t len;
 
 		dst = psinfo->buf;
-		hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part);
+		if (psinfo->flags & PSTORE_NO_HEADINGS)
+			hsize = 0;
+		else
+			hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount,
+					part);
 		size = psinfo->bufsize - hsize;
 		dst += hsize;
 
@@ -237,6 +241,9 @@ int pstore_register(struct pstore_info *psi)
 		return -EINVAL;
 	}
 
+	if (psinfo->flags & PSTORE_MAX_KMSG_BYTES)
+		kmsg_bytes = ULONG_MAX;
+
 	if (pstore_is_mounted())
 		pstore_get_records(0);
 
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index ee3034a..55ab23f 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -40,9 +40,13 @@ enum pstore_type_id {
 
 struct module;
 
+#define PSTORE_NO_HEADINGS	BIT(0)
+#define PSTORE_MAX_KMSG_BYTES	BIT(1)
+
 struct pstore_info {
 	struct module	*owner;
 	char		*name;
+	unsigned int	flags;
 	spinlock_t	buf_lock;	/* serialize access to 'buf' */
 	char		*buf;
 	size_t		bufsize;
-- 
1.7.9.5


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

* [PATCH 2/8] pstore: add debugfs support for causing dumps and panics
  2012-10-15 11:40 [PATCH 0/8] pstore: add interface for dumpers and add task list dumper dragos.tatulea
  2012-10-15 11:40 ` [PATCH 1/8] pstore: add flags dragos.tatulea
@ 2012-10-15 11:40 ` dragos.tatulea
  2012-10-15 11:40 ` [PATCH 3/8] pstore: add support for external writers dragos.tatulea
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: dragos.tatulea @ 2012-10-15 11:40 UTC (permalink / raw)
  To: cbouatmailru, linux-kernel; +Cc: adrian.hunter, octavian.purdila

From: Adrian Hunter <adrian.hunter@intel.com>

There are 2 debugfs files:

	pstore/dump	writing a kmsg dump reason code
			will cause a dump to persistent
			storage

	pstore/panic	writing anything will cause
			a panic

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 fs/pstore/platform.c |   51 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index c4ea778..9d65723 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -33,6 +33,7 @@
 #include <linux/hardirq.h>
 #include <linux/jiffies.h>
 #include <linux/workqueue.h>
+#include <linux/debugfs.h>
 
 #include "internal.h"
 
@@ -206,6 +207,54 @@ static int pstore_write_compat(enum pstore_type_id type,
 	return psi->write_buf(type, reason, id, part, psinfo->buf, size, psi);
 }
 
+#ifdef CONFIG_DEBUG_FS
+
+static DEFINE_SPINLOCK(dbg_lock);
+
+static int dbg_dump(void *data, u64 val)
+{
+	unsigned long flags;
+
+	switch (val) {
+	case KMSG_DUMP_PANIC:
+	case KMSG_DUMP_OOPS:
+	case KMSG_DUMP_EMERG:
+	case KMSG_DUMP_RESTART:
+	case KMSG_DUMP_HALT:
+	case KMSG_DUMP_POWEROFF:
+		spin_lock_irqsave(&dbg_lock, flags);
+		kmsg_dump(val);
+		spin_unlock_irqrestore(&dbg_lock, flags);
+		return 0;
+	}
+	return -EINVAL;
+}
+DEFINE_SIMPLE_ATTRIBUTE(dbg_dump_fops, NULL, dbg_dump, "%llu\n");
+
+static int dbg_panic(void *data, u64 val)
+{
+	panic(KERN_EMERG "pstore debugging panic!\n");
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(dbg_panic_fops, NULL, dbg_panic, "%llu\n");
+
+static void pstore_debugfs_init(void)
+{
+	struct dentry *root;
+
+	root = debugfs_create_dir("pstore", NULL);
+	debugfs_create_file("dump", S_IWUSR, root, NULL, &dbg_dump_fops);
+	debugfs_create_file("panic", S_IWUSR, root, NULL, &dbg_panic_fops);
+}
+
+#else
+
+static inline void pstore_debugfs_init(void)
+{
+}
+
+#endif
+
 /*
  * platform specific persistent storage driver registers with
  * us here. If pstore is already mounted, call the platform
@@ -257,6 +306,8 @@ int pstore_register(struct pstore_info *psi)
 		add_timer(&pstore_timer);
 	}
 
+	pstore_debugfs_init();
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(pstore_register);
-- 
1.7.9.5


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

* [PATCH 3/8] pstore: add support for external writers
  2012-10-15 11:40 [PATCH 0/8] pstore: add interface for dumpers and add task list dumper dragos.tatulea
  2012-10-15 11:40 ` [PATCH 1/8] pstore: add flags dragos.tatulea
  2012-10-15 11:40 ` [PATCH 2/8] pstore: add debugfs support for causing dumps and panics dragos.tatulea
@ 2012-10-15 11:40 ` dragos.tatulea
  2012-10-15 11:40 ` [PATCH 4/8] pstore: allow storing different type id's in ram backend dragos.tatulea
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: dragos.tatulea @ 2012-10-15 11:40 UTC (permalink / raw)
  To: cbouatmailru, linux-kernel; +Cc: adrian.hunter, octavian.purdila

From: Adrian Hunter <adrian.hunter@intel.com>

Other modules that may wish to write to persistent storage
are supported by adding a notifier and write function.

The notifier has 3 events: PSTORE_BEGIN, PSTORE_DUMP and
PSTORE_END.  External writers use the PSTORE_DUMP event
whereas the PSTORE_BEGIN and PSTORE_END can be used by
platform code to ensure the back end is powered up.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 fs/pstore/platform.c   |   88 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pstore.h |   43 +++++++++++++++++++----
 2 files changed, 124 insertions(+), 7 deletions(-)

diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 9d65723..63ff377 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -34,6 +34,7 @@
 #include <linux/jiffies.h>
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
+#include <linux/notifier.h>
 
 #include "internal.h"
 
@@ -74,6 +75,20 @@ void pstore_set_kmsg_bytes(int bytes)
 	kmsg_bytes = bytes;
 }
 
+static ATOMIC_NOTIFIER_HEAD(pstore_notifiers);
+
+int pstore_notifier_register(struct notifier_block *n)
+{
+	return atomic_notifier_chain_register(&pstore_notifiers, n);
+}
+EXPORT_SYMBOL_GPL(pstore_notifier_register);
+
+int pstore_notifier_unregister(struct notifier_block *n)
+{
+	return atomic_notifier_chain_unregister(&pstore_notifiers, n);
+}
+EXPORT_SYMBOL_GPL(pstore_notifier_unregister);
+
 /* Tag each group of saved records with a sequence number */
 static int	oopscount;
 
@@ -97,6 +112,26 @@ static const char *get_reason_str(enum kmsg_dump_reason reason)
 	}
 }
 
+static int pstore_ext_flush(void)
+{
+	int ret;
+
+	if (!psinfo->ext_len)
+		return 0;
+
+	ret = psinfo->write(psinfo->ext_type, psinfo->ext_reason,
+			    &psinfo->ext_id, psinfo->ext_part++,
+			    psinfo->ext_len, psinfo);
+
+	if (ret == 0 && psinfo->ext_reason == KMSG_DUMP_OOPS &&
+	    pstore_is_mounted())
+		pstore_new_entry = 1;
+
+	psinfo->ext_len = 0;
+
+	return ret;
+}
+
 /*
  * callback from kmsg_dump. (s2,l2) has the most recently
  * written bytes, older bytes are in (s1,l1). Save as much
@@ -122,6 +157,15 @@ static void pstore_dump(struct kmsg_dumper *dumper,
 	} else
 		spin_lock_irqsave(&psinfo->buf_lock, flags);
 	oopscount++;
+
+	psinfo->ext_id = 0;
+	psinfo->ext_len = 0;
+	psinfo->ext_part = 0;
+	psinfo->ext_type = PSTORE_TYPE_UNKNOWN;
+	psinfo->ext_reason = reason;
+
+	atomic_notifier_call_chain(&pstore_notifiers, PSTORE_BEGIN, psinfo);
+
 	while (total < kmsg_bytes) {
 		char *dst;
 		unsigned long size;
@@ -148,6 +192,13 @@ static void pstore_dump(struct kmsg_dumper *dumper,
 		total += hsize + len;
 		part++;
 	}
+
+	atomic_notifier_call_chain(&pstore_notifiers, PSTORE_DUMP, psinfo);
+
+	pstore_ext_flush();
+
+	atomic_notifier_call_chain(&pstore_notifiers, PSTORE_END, psinfo);
+
 	if (in_nmi()) {
 		if (is_locked)
 			spin_unlock(&psinfo->buf_lock);
@@ -368,5 +419,42 @@ static void pstore_timefunc(unsigned long dummy)
 	mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms));
 }
 
+/* pstore_write must only be called from PSTORE_DUMP notifier callbacks */
+int pstore_write(enum pstore_type_id type, const char *buf, size_t size)
+{
+	size_t len;
+	int err = 0, err2;
+
+	if (!psinfo)
+		return -ENODEV;
+
+	/*
+	 * No locking is needed because pstore_write is called only from
+	 * PSTORE_DUMP notifier callbacks.
+	 */
+
+	if (type != psinfo->ext_type) {
+		err = pstore_ext_flush();
+		psinfo->ext_type = type;
+		psinfo->ext_part = 1;
+	}
+
+	while (size) {
+		len = min(size, psinfo->bufsize - psinfo->ext_len);
+		memcpy(psinfo->buf + psinfo->ext_len, buf, len);
+		psinfo->ext_len += len;
+		buf += len;
+		size -= len;
+		if (psinfo->ext_len == psinfo->bufsize) {
+			err2 = pstore_ext_flush();
+			if (err2 && !err)
+				err = err2;
+		}
+	}
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(pstore_write);
+
 module_param(backend, charp, 0444);
 MODULE_PARM_DESC(backend, "Pstore backend to use");
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index 55ab23f..1bf7f4b 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -40,17 +40,27 @@ enum pstore_type_id {
 
 struct module;
 
+/* Notifier events */
+#define PSTORE_BEGIN		1
+#define PSTORE_DUMP		2
+#define PSTORE_END		3
+
 #define PSTORE_NO_HEADINGS	BIT(0)
 #define PSTORE_MAX_KMSG_BYTES	BIT(1)
 
 struct pstore_info {
-	struct module	*owner;
-	char		*name;
-	unsigned int	flags;
-	spinlock_t	buf_lock;	/* serialize access to 'buf' */
-	char		*buf;
-	size_t		bufsize;
-	struct mutex	read_mutex;	/* serialize open/read/close */
+	struct module		*owner;
+	char			*name;
+	unsigned int		flags;
+	spinlock_t		buf_lock;	/* serialize access to 'buf' */
+	char			*buf;
+	size_t			bufsize;
+	struct mutex		read_mutex;	/* serialize open/read/close */
+	u64			ext_id;
+	size_t			ext_len;
+	unsigned int		ext_part;
+	enum pstore_type_id	ext_type;
+	enum kmsg_dump_reason	ext_reason;
 	int		(*open)(struct pstore_info *psi);
 	int		(*close)(struct pstore_info *psi);
 	ssize_t		(*read)(u64 *id, enum pstore_type_id *type,
@@ -70,12 +80,31 @@ struct pstore_info {
 
 #ifdef CONFIG_PSTORE
 extern int pstore_register(struct pstore_info *);
+extern int pstore_notifier_register(struct notifier_block *n);
+extern int pstore_notifier_unregister(struct notifier_block *n);
+/* pstore_write must only be called from PSTORE_DUMP notifier callbacks */
+extern int pstore_write(enum pstore_type_id type, const char *buf, size_t size);
 #else
 static inline int
 pstore_register(struct pstore_info *psi)
 {
 	return -ENODEV;
 }
+static inline int
+pstore_notifier_register(struct notifier_block *n)
+{
+	return 0;
+}
+static inline int
+pstore_notifier_unregister(struct notifier_block *n)
+{
+	return 0;
+}
+static inline int
+pstore_write(enum pstore_type_id type, const char *buf, size_t size)
+{
+	return 0;
+}
 #endif
 
 #endif /*_LINUX_PSTORE_H*/
-- 
1.7.9.5


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

* [PATCH 4/8] pstore: allow storing different type id's in ram backend
  2012-10-15 11:40 [PATCH 0/8] pstore: add interface for dumpers and add task list dumper dragos.tatulea
                   ` (2 preceding siblings ...)
  2012-10-15 11:40 ` [PATCH 3/8] pstore: add support for external writers dragos.tatulea
@ 2012-10-15 11:40 ` dragos.tatulea
  2012-10-15 11:40 ` [PATCH 5/8] pstore: add task list dumper dragos.tatulea
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: dragos.tatulea @ 2012-10-15 11:40 UTC (permalink / raw)
  To: cbouatmailru, linux-kernel
  Cc: adrian.hunter, octavian.purdila, Dragos Tatulea

From: Dragos Tatulea <dragos.tatulea@intel.com>

Added pstore_type_id in message header when storing to ram.
On write, take into account the contents of this header and
set the type accordingly.

Signed-off-by: Dragos Tatulea <dragos.tatulea@intel.com>
---
 fs/pstore/ram.c |   18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 1a4f6da..e1684ef 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -157,23 +157,30 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
 	time->tv_nsec = 0;
 
 	size = persistent_ram_old_size(prz);
+	if (!size)
+		return 0;
 	*buf = kmalloc(size, GFP_KERNEL);
 	if (*buf == NULL)
 		return -ENOMEM;
 	memcpy(*buf, persistent_ram_old(prz), size);
+	/* Read header. */
+	sscanf(*buf, "%u" RAMOOPS_KERNMSG_HDR "%lu.%lu",
+		type, &time->tv_sec, &time->tv_nsec);
+	time->tv_nsec *= 1000;
 
 	return size;
 }
 
-static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz)
+static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz,
+				     enum pstore_type_id type)
 {
 	char *hdr;
 	struct timeval timestamp;
 	size_t len;
 
 	do_gettimeofday(&timestamp);
-	hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n",
-		(long)timestamp.tv_sec, (long)timestamp.tv_usec);
+	hdr = kasprintf(GFP_ATOMIC, "%u" RAMOOPS_KERNMSG_HDR "%lu.%lu\n",
+		type, (long)timestamp.tv_sec, (long)timestamp.tv_usec);
 	WARN_ON_ONCE(!hdr);
 	len = hdr ? strlen(hdr) : 0;
 	persistent_ram_write(prz, hdr, len);
@@ -204,9 +211,6 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
 		return 0;
 	}
 
-	if (type != PSTORE_TYPE_DMESG)
-		return -EINVAL;
-
 	/* Out of the various dmesg dump types, ramoops is currently designed
 	 * to only store crash logs, rather than storing general kernel logs.
 	 */
@@ -226,7 +230,7 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
 	if (part != 1)
 		return -ENOSPC;
 
-	hlen = ramoops_write_kmsg_hdr(prz);
+	hlen = ramoops_write_kmsg_hdr(prz, type);
 	if (size + hlen > prz->buffer_size)
 		size = prz->buffer_size - hlen;
 	persistent_ram_write(prz, buf, size);
-- 
1.7.9.5


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

* [PATCH 5/8] pstore: add task list dumper
  2012-10-15 11:40 [PATCH 0/8] pstore: add interface for dumpers and add task list dumper dragos.tatulea
                   ` (3 preceding siblings ...)
  2012-10-15 11:40 ` [PATCH 4/8] pstore: allow storing different type id's in ram backend dragos.tatulea
@ 2012-10-15 11:40 ` dragos.tatulea
  2012-10-15 11:40 ` [PATCH 6/8] pstore: do not run timer while pstore is not mounted dragos.tatulea
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: dragos.tatulea @ 2012-10-15 11:40 UTC (permalink / raw)
  To: cbouatmailru, linux-kernel
  Cc: adrian.hunter, octavian.purdila, Dragos Tatulea

From: Dragos Tatulea <dragos.tatulea@intel.com>

The task dumper can dump task information during a panic.
This is equivalent to a magic sysrq 't' command but
the result is captured from the console and written
to persistent storage.  Note that this happens after
pstore dumps kernel messages because the task dump will
overwrite other kernel messages.

There is a single module parameter "enabled" which must
be used to enable task dumping.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Dragos Tatulea <dragos.tatulea@intel.com>
---
 fs/pstore/Kconfig      |   12 ++++++
 fs/pstore/Makefile     |    1 +
 fs/pstore/dump_tasks.c |  107 ++++++++++++++++++++++++++++++++++++++++++++++++
 fs/pstore/inode.c      |    3 ++
 include/linux/pstore.h |    1 +
 5 files changed, 124 insertions(+)
 create mode 100644 fs/pstore/dump_tasks.c

diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index ca71db6..ee967c5 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -48,3 +48,15 @@ config PSTORE_RAM
 	  "ramoops.ko".
 
 	  For more information, see Documentation/ramoops.txt.
+
+config PSTORE_DUMP_TASKS
+	bool "Dump task information"
+	default n
+	depends on PSTORE
+	help
+	  This option allows a dump of task information during a
+	  panic.  This is equivalent to a magic sysrq 't' command
+	  but the result is captured from the console and written
+	  to persistent storage.  Note that this happens after
+	  pstore dumps kernel messages because the task dump will
+	  overwrite other kernel messages.
diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile
index 4c9095c..14b5c83 100644
--- a/fs/pstore/Makefile
+++ b/fs/pstore/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_PSTORE_FTRACE)	+= ftrace.o
 
 ramoops-objs += ram.o ram_core.o
 obj-$(CONFIG_PSTORE_RAM)	+= ramoops.o
+obj-$(CONFIG_PSTORE_DUMP_TASKS)	+= dump_tasks.o
diff --git a/fs/pstore/dump_tasks.c b/fs/pstore/dump_tasks.c
new file mode 100644
index 0000000..b010b35
--- /dev/null
+++ b/fs/pstore/dump_tasks.c
@@ -0,0 +1,107 @@
+/*
+ * Persistent Storage task dumper
+ *
+ * Copyright (C) 2012 Intel Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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/console.h>
+#include <linux/sched.h>
+#include <linux/hardirq.h>
+#include <linux/delay.h>
+#include <linux/pstore.h>
+
+static int enabled;
+
+static void pstore_dump_tasks(struct console *console, const char *s,
+			      unsigned int count)
+{
+	pstore_write(PSTORE_TYPE_TASK_DUMP, s, count);
+}
+
+static struct console pstore_dump_tasks_console = {
+	.name	= "dump_tasks",
+	.write	= pstore_dump_tasks,
+	.flags	= CON_ANYTIME | CON_ENABLED,
+	.index	= -1,
+};
+
+static int pstore_notifier_cb(struct notifier_block *nb, unsigned long event,
+			      void *_psinfo)
+{
+	struct pstore_info *psinfo = _psinfo;
+	int retry;
+
+	if (psinfo->ext_reason != KMSG_DUMP_PANIC || !enabled)
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case PSTORE_DUMP:
+		pstore_dump_tasks_console.flags |= CON_ENABLED;
+		show_state();
+
+		/* Make sure data gets pushed to console drivers.
+		 * Yes, can take a long time to write everything,
+		 * shortening the length increases the chances of
+		 * ending up with an incomplete log.
+		 */
+		retry = 100;
+		while (retry) {
+			if (console_trylock()) {
+				console_unlock();
+				break;
+			} else {
+				mdelay(100);
+				retry--;
+			}
+		}
+
+		break;
+	case PSTORE_END:
+		pstore_dump_tasks_console.flags &= ~CON_ENABLED;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block pstore_notifier = {
+	.notifier_call = pstore_notifier_cb,
+	/* Leave other dumpers do their job. This one can take longer. */
+	.priority = -1,
+};
+
+static int __init pstore_dump_tasks_init(void)
+{
+	register_console(&pstore_dump_tasks_console);
+	console_stop(&pstore_dump_tasks_console);
+	pstore_notifier_register(&pstore_notifier);
+	return 0;
+}
+module_init(pstore_dump_tasks_init);
+
+static void __exit pstore_dump_tasks_exit(void)
+{
+	pstore_notifier_unregister(&pstore_notifier);
+	unregister_console(&pstore_dump_tasks_console);
+}
+module_exit(pstore_dump_tasks_exit);
+
+module_param(enabled, int,  S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(enabled, "set to 1 to enable task dump, 0 to disable (default 0)");
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_DESCRIPTION("Persistent Storage task dumper");
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 4ab572e..4800c09 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -321,6 +321,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id,
 	case PSTORE_TYPE_MCE:
 		sprintf(name, "mce-%s-%lld", psname, id);
 		break;
+	case PSTORE_TYPE_TASK_DUMP:
+		sprintf(name, "tasks-%s-%lld", psname, id);
+		break;
 	case PSTORE_TYPE_UNKNOWN:
 		sprintf(name, "unknown-%s-%lld", psname, id);
 		break;
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index 1bf7f4b..48dcafb 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -35,6 +35,7 @@ enum pstore_type_id {
 	PSTORE_TYPE_MCE		= 1,
 	PSTORE_TYPE_CONSOLE	= 2,
 	PSTORE_TYPE_FTRACE	= 3,
+	PSTORE_TYPE_TASK_DUMP	= 4,
 	PSTORE_TYPE_UNKNOWN	= 255
 };
 
-- 
1.7.9.5


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

* [PATCH 6/8] pstore: do not run timer while pstore is not mounted
  2012-10-15 11:40 [PATCH 0/8] pstore: add interface for dumpers and add task list dumper dragos.tatulea
                   ` (4 preceding siblings ...)
  2012-10-15 11:40 ` [PATCH 5/8] pstore: add task list dumper dragos.tatulea
@ 2012-10-15 11:40 ` dragos.tatulea
  2012-10-15 11:40 ` [PATCH 7/8] pstore: make sure pstore_write exists on flush error dragos.tatulea
  2012-10-15 11:40 ` [PATCH 8/8] pstore: max out console log level during sysfs dump switch dragos.tatulea
  7 siblings, 0 replies; 10+ messages in thread
From: dragos.tatulea @ 2012-10-15 11:40 UTC (permalink / raw)
  To: cbouatmailru, linux-kernel; +Cc: adrian.hunter, octavian.purdila

From: Adrian Hunter <adrian.hunter@intel.com>

A timer is used to periodically check for new dumps.
The timer is not needed unless pstore is mounted,
so disable it otherwise.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 fs/pstore/inode.c    |    3 +++
 fs/pstore/internal.h |    2 ++
 fs/pstore/platform.c |   36 +++++++++++++++++++++++++++++-------
 3 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 4800c09..5e20a8d 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -397,6 +397,8 @@ static int pstore_fill_super(struct super_block *sb, void *data, int silent)
 
 	pstore_get_records(0);
 
+	pstore_add_timer();
+
 	return 0;
 }
 
@@ -408,6 +410,7 @@ static struct dentry *pstore_mount(struct file_system_type *fs_type,
 
 static void pstore_kill_sb(struct super_block *sb)
 {
+	pstore_del_timer();
 	kill_litter_super(sb);
 	pstore_sb = NULL;
 }
diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
index 4847f58..c7b8197 100644
--- a/fs/pstore/internal.h
+++ b/fs/pstore/internal.h
@@ -54,4 +54,6 @@ extern int	pstore_mkfile(enum pstore_type_id, char *psname, u64 id,
 			      struct timespec time, struct pstore_info *psi);
 extern int	pstore_is_mounted(void);
 
+extern void pstore_add_timer(void);
+extern void pstore_del_timer(void);
 #endif
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 63ff377..3a4c38f 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -54,6 +54,8 @@ static int pstore_new_entry;
 
 static void pstore_timefunc(unsigned long);
 static DEFINE_TIMER(pstore_timer, pstore_timefunc, 0, 0);
+static DEFINE_SPINLOCK(pstore_timer_lock);
+static int pstore_timer_on;
 
 static void pstore_dowork(struct work_struct *);
 static DECLARE_WORK(pstore_work, pstore_dowork);
@@ -351,12 +353,6 @@ int pstore_register(struct pstore_info *psi)
 	pstore_register_console();
 	pstore_register_ftrace();
 
-	if (pstore_update_ms >= 0) {
-		pstore_timer.expires = jiffies +
-			msecs_to_jiffies(pstore_update_ms);
-		add_timer(&pstore_timer);
-	}
-
 	pstore_debugfs_init();
 
 	return 0;
@@ -411,12 +407,38 @@ static void pstore_dowork(struct work_struct *work)
 
 static void pstore_timefunc(unsigned long dummy)
 {
+	unsigned long flags;
+
 	if (pstore_new_entry) {
 		pstore_new_entry = 0;
 		schedule_work(&pstore_work);
 	}
 
-	mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms));
+	spin_lock_irqsave(&pstore_timer_lock, flags);
+	if (pstore_timer_on)
+		mod_timer(&pstore_timer,
+				jiffies + msecs_to_jiffies(pstore_update_ms));
+	spin_unlock_irqrestore(&pstore_timer_lock, flags);
+}
+
+void pstore_add_timer(void)
+{
+	pstore_timer_on = 1;
+	if (pstore_update_ms >= 0) {
+		pstore_timer.expires = jiffies +
+			msecs_to_jiffies(pstore_update_ms);
+		add_timer(&pstore_timer);
+	}
+}
+
+void pstore_del_timer(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&pstore_timer_lock, flags);
+	pstore_timer_on = 0;
+	spin_unlock_irqrestore(&pstore_timer_lock, flags);
+	del_timer_sync(&pstore_timer);
 }
 
 /* pstore_write must only be called from PSTORE_DUMP notifier callbacks */
-- 
1.7.9.5


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

* [PATCH 7/8] pstore: make sure pstore_write exists on flush error
  2012-10-15 11:40 [PATCH 0/8] pstore: add interface for dumpers and add task list dumper dragos.tatulea
                   ` (5 preceding siblings ...)
  2012-10-15 11:40 ` [PATCH 6/8] pstore: do not run timer while pstore is not mounted dragos.tatulea
@ 2012-10-15 11:40 ` dragos.tatulea
  2012-10-15 11:40 ` [PATCH 8/8] pstore: max out console log level during sysfs dump switch dragos.tatulea
  7 siblings, 0 replies; 10+ messages in thread
From: dragos.tatulea @ 2012-10-15 11:40 UTC (permalink / raw)
  To: cbouatmailru, linux-kernel
  Cc: adrian.hunter, octavian.purdila, Dragos Tatulea

From: Dragos Tatulea <dragos.tatulea@intel.com>

Return error if flushing to backend failed.

Signed-off-by: Dragos Tatulea <dragos.tatulea@intel.com>
---
 fs/pstore/platform.c |    8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 3a4c38f..25f59ed 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -445,7 +445,7 @@ void pstore_del_timer(void)
 int pstore_write(enum pstore_type_id type, const char *buf, size_t size)
 {
 	size_t len;
-	int err = 0, err2;
+	int err = 0;
 
 	if (!psinfo)
 		return -ENODEV;
@@ -461,16 +461,14 @@ int pstore_write(enum pstore_type_id type, const char *buf, size_t size)
 		psinfo->ext_part = 1;
 	}
 
-	while (size) {
+	while (size && !err) {
 		len = min(size, psinfo->bufsize - psinfo->ext_len);
 		memcpy(psinfo->buf + psinfo->ext_len, buf, len);
 		psinfo->ext_len += len;
 		buf += len;
 		size -= len;
 		if (psinfo->ext_len == psinfo->bufsize) {
-			err2 = pstore_ext_flush();
-			if (err2 && !err)
-				err = err2;
+			err = pstore_ext_flush();
 		}
 	}
 
-- 
1.7.9.5


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

* [PATCH 8/8] pstore: max out console log level during sysfs dump switch
  2012-10-15 11:40 [PATCH 0/8] pstore: add interface for dumpers and add task list dumper dragos.tatulea
                   ` (6 preceding siblings ...)
  2012-10-15 11:40 ` [PATCH 7/8] pstore: make sure pstore_write exists on flush error dragos.tatulea
@ 2012-10-15 11:40 ` dragos.tatulea
  7 siblings, 0 replies; 10+ messages in thread
From: dragos.tatulea @ 2012-10-15 11:40 UTC (permalink / raw)
  To: cbouatmailru, linux-kernel
  Cc: adrian.hunter, octavian.purdila, Dragos Tatulea

From: Dragos Tatulea <dragos.tatulea@intel.com>

Otherwise we might miss out on some pstore dumpers that use
printks below current log level.

Signed-off-by: Dragos Tatulea <dragos.tatulea@intel.com>
---
 fs/pstore/platform.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 25f59ed..e3ad13e 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -267,6 +267,7 @@ static DEFINE_SPINLOCK(dbg_lock);
 static int dbg_dump(void *data, u64 val)
 {
 	unsigned long flags;
+	int saved_loglevel;
 
 	switch (val) {
 	case KMSG_DUMP_PANIC:
@@ -276,7 +277,10 @@ static int dbg_dump(void *data, u64 val)
 	case KMSG_DUMP_HALT:
 	case KMSG_DUMP_POWEROFF:
 		spin_lock_irqsave(&dbg_lock, flags);
+		saved_loglevel = console_loglevel;
+		console_loglevel =  15;
 		kmsg_dump(val);
+		console_loglevel = saved_loglevel;
 		spin_unlock_irqrestore(&dbg_lock, flags);
 		return 0;
 	}
-- 
1.7.9.5


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

* [PATCH 3/8] pstore: add support for external writers
  2012-10-15 11:38 [PATCH 0/8] pstore: add interface for dumpers and add task list dumper dragos.tatulea
@ 2012-10-15 11:38 ` dragos.tatulea
  0 siblings, 0 replies; 10+ messages in thread
From: dragos.tatulea @ 2012-10-15 11:38 UTC (permalink / raw)
  To: cbouatmailru, linux-kernel; +Cc: adrian.hunter, octavian.purdila

From: Adrian Hunter <adrian.hunter@intel.com>

Other modules that may wish to write to persistent storage
are supported by adding a notifier and write function.

The notifier has 3 events: PSTORE_BEGIN, PSTORE_DUMP and
PSTORE_END.  External writers use the PSTORE_DUMP event
whereas the PSTORE_BEGIN and PSTORE_END can be used by
platform code to ensure the back end is powered up.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
--
 fs/pstore/platform.c   |   88 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pstore.h |   43 +++++++++++++++++++----
 2 files changed, 124 insertions(+), 7 deletions(-)

diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 9d65723..63ff377 100644
-- a/fs/pstore/platform.c
++ b/fs/pstore/platform.c
@@ -34,6 +34,7 @@
 #include <linux/jiffies.h>
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
#include <linux/notifier.h>
 
 #include "internal.h"
 
@@ -74,6 +75,20 @@ void pstore_set_kmsg_bytes(int bytes)
 	kmsg_bytes = bytes;
 }
 
static ATOMIC_NOTIFIER_HEAD(pstore_notifiers);

int pstore_notifier_register(struct notifier_block *n)
{
	return atomic_notifier_chain_register(&pstore_notifiers, n);
}
EXPORT_SYMBOL_GPL(pstore_notifier_register);

int pstore_notifier_unregister(struct notifier_block *n)
{
	return atomic_notifier_chain_unregister(&pstore_notifiers, n);
}
EXPORT_SYMBOL_GPL(pstore_notifier_unregister);

 /* Tag each group of saved records with a sequence number */
 static int	oopscount;
 
@@ -97,6 +112,26 @@ static const char *get_reason_str(enum kmsg_dump_reason reason)
 	}
 }
 
static int pstore_ext_flush(void)
{
	int ret;

	if (!psinfo->ext_len)
		return 0;

	ret = psinfo->write(psinfo->ext_type, psinfo->ext_reason,
			    &psinfo->ext_id, psinfo->ext_part++,
			    psinfo->ext_len, psinfo);

	if (ret == 0 && psinfo->ext_reason == KMSG_DUMP_OOPS &&
	    pstore_is_mounted())
		pstore_new_entry = 1;

	psinfo->ext_len = 0;

	return ret;
}

 /*
  * callback from kmsg_dump. (s2,l2) has the most recently
  * written bytes, older bytes are in (s1,l1). Save as much
@@ -122,6 +157,15 @@ static void pstore_dump(struct kmsg_dumper *dumper,
 	} else
 		spin_lock_irqsave(&psinfo->buf_lock, flags);
 	oopscount++;

	psinfo->ext_id = 0;
	psinfo->ext_len = 0;
	psinfo->ext_part = 0;
	psinfo->ext_type = PSTORE_TYPE_UNKNOWN;
	psinfo->ext_reason = reason;

	atomic_notifier_call_chain(&pstore_notifiers, PSTORE_BEGIN, psinfo);

 	while (total < kmsg_bytes) {
 		char *dst;
 		unsigned long size;
@@ -148,6 +192,13 @@ static void pstore_dump(struct kmsg_dumper *dumper,
 		total += hsize + len;
 		part++;
 	}

	atomic_notifier_call_chain(&pstore_notifiers, PSTORE_DUMP, psinfo);

	pstore_ext_flush();

	atomic_notifier_call_chain(&pstore_notifiers, PSTORE_END, psinfo);

 	if (in_nmi()) {
 		if (is_locked)
 			spin_unlock(&psinfo->buf_lock);
@@ -368,5 +419,42 @@ static void pstore_timefunc(unsigned long dummy)
 	mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms));
 }
 
/* pstore_write must only be called from PSTORE_DUMP notifier callbacks */
int pstore_write(enum pstore_type_id type, const char *buf, size_t size)
{
	size_t len;
	int err = 0, err2;

	if (!psinfo)
		return -ENODEV;

	/*
	 * No locking is needed because pstore_write is called only from
	 * PSTORE_DUMP notifier callbacks.
	 */

	if (type != psinfo->ext_type) {
		err = pstore_ext_flush();
		psinfo->ext_type = type;
		psinfo->ext_part = 1;
	}

	while (size) {
		len = min(size, psinfo->bufsize - psinfo->ext_len);
		memcpy(psinfo->buf + psinfo->ext_len, buf, len);
		psinfo->ext_len += len;
		buf += len;
		size -= len;
		if (psinfo->ext_len == psinfo->bufsize) {
			err2 = pstore_ext_flush();
			if (err2 && !err)
				err = err2;
		}
	}

	return err;
}
EXPORT_SYMBOL_GPL(pstore_write);

 module_param(backend, charp, 0444);
 MODULE_PARM_DESC(backend, "Pstore backend to use");
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index 55ab23f..1bf7f4b 100644
-- a/include/linux/pstore.h
++ b/include/linux/pstore.h
@@ -40,17 +40,27 @@ enum pstore_type_id {
 
 struct module;
 
/* Notifier events */
#define PSTORE_BEGIN		1
#define PSTORE_DUMP		2
#define PSTORE_END		3

 #define PSTORE_NO_HEADINGS	BIT(0)
 #define PSTORE_MAX_KMSG_BYTES	BIT(1)
 
 struct pstore_info {
	struct module	*owner;
	char		*name;
	unsigned int	flags;
	spinlock_t	buf_lock;	/* serialize access to 'buf' */
	char		*buf;
	size_t		bufsize;
	struct mutex	read_mutex;	/* serialize open/read/close */
	struct module		*owner;
	char			*name;
	unsigned int		flags;
	spinlock_t		buf_lock;	/* serialize access to 'buf' */
	char			*buf;
	size_t			bufsize;
	struct mutex		read_mutex;	/* serialize open/read/close */
	u64			ext_id;
	size_t			ext_len;
	unsigned int		ext_part;
	enum pstore_type_id	ext_type;
	enum kmsg_dump_reason	ext_reason;
 	int		(*open)(struct pstore_info *psi);
 	int		(*close)(struct pstore_info *psi);
 	ssize_t		(*read)(u64 *id, enum pstore_type_id *type,
@@ -70,12 +80,31 @@ struct pstore_info {
 
 #ifdef CONFIG_PSTORE
 extern int pstore_register(struct pstore_info *);
extern int pstore_notifier_register(struct notifier_block *n);
extern int pstore_notifier_unregister(struct notifier_block *n);
/* pstore_write must only be called from PSTORE_DUMP notifier callbacks */
extern int pstore_write(enum pstore_type_id type, const char *buf, size_t size);
 #else
 static inline int
 pstore_register(struct pstore_info *psi)
 {
 	return -ENODEV;
 }
static inline int
pstore_notifier_register(struct notifier_block *n)
{
	return 0;
}
static inline int
pstore_notifier_unregister(struct notifier_block *n)
{
	return 0;
}
static inline int
pstore_write(enum pstore_type_id type, const char *buf, size_t size)
{
	return 0;
}
 #endif
 
 #endif /*_LINUX_PSTORE_H*/
- 
1.7.9.5


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

end of thread, other threads:[~2012-10-15 11:41 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-15 11:40 [PATCH 0/8] pstore: add interface for dumpers and add task list dumper dragos.tatulea
2012-10-15 11:40 ` [PATCH 1/8] pstore: add flags dragos.tatulea
2012-10-15 11:40 ` [PATCH 2/8] pstore: add debugfs support for causing dumps and panics dragos.tatulea
2012-10-15 11:40 ` [PATCH 3/8] pstore: add support for external writers dragos.tatulea
2012-10-15 11:40 ` [PATCH 4/8] pstore: allow storing different type id's in ram backend dragos.tatulea
2012-10-15 11:40 ` [PATCH 5/8] pstore: add task list dumper dragos.tatulea
2012-10-15 11:40 ` [PATCH 6/8] pstore: do not run timer while pstore is not mounted dragos.tatulea
2012-10-15 11:40 ` [PATCH 7/8] pstore: make sure pstore_write exists on flush error dragos.tatulea
2012-10-15 11:40 ` [PATCH 8/8] pstore: max out console log level during sysfs dump switch dragos.tatulea
  -- strict thread matches above, loose matches on Subject: below --
2012-10-15 11:38 [PATCH 0/8] pstore: add interface for dumpers and add task list dumper dragos.tatulea
2012-10-15 11:38 ` [PATCH 3/8] pstore: add support for external writers dragos.tatulea

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).