[RFC][PATCH -mmotm 1/4] Add static function calls of pstore to kexec path
Seiji Aguchi
seiji.aguchi at hds.com
Tue Jul 19 14:24:27 EDT 2011
Hi,
This patch adds static function calls so that both pstore and APEI storage backend can work reliably in kexec path.
kernel/kexec.c
- Add pstore_kmsg_dump_in_interrupt(KMSG_DUMP_KEXEC) just after machine_crash_shutdown() so that pstore can
work with one cpu.
kernel/printk.c
- Introduce get_logbuf_nolock() so that pstore can get values of logbuf without taking lock.
fs/pstore/platform.c
- Introduce pstore_kmsg_dump_in_interrupt() so that pstore/APEI storage backend can output kernel messages without taking lock.
pstore_dump()
- Add error checks below because pstore_dump() is called from kmsg_dump(KMSG_DUMP_KEXEC) directly.
- Skip if no driver is registered
- Skip if there is a driver calling pstore_register()/pstore_unregister()
- Remove mutex_lock from kexec path
TODO:
APEI storage backend will work with this patch.
However, I don't have any access to servers capable of APEI storage backend.
Please help to test my patch.
Signed-off-by: Seiji Aguchi <seiji.aguchi at hds.com>
---
fs/pstore/platform.c | 27 +++++++++++++++++++++++++--
include/linux/kmsg_dump.h | 1 +
include/linux/pstore.h | 9 +++++++++
kernel/kexec.c | 3 +++
kernel/printk.c | 29 +++++++++++++++++++++++++++++
5 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index f2c3ff2..85e0a9c 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -74,7 +74,17 @@ static void pstore_dump(struct kmsg_dumper *dumper,
else
why = "Unknown";
- mutex_lock(&psinfo->buf_mutex);
+ switch (reason) {
+ case KMSG_DUMP_KEXEC:
+ /* Skip if there is no driver or there is a driver calling
+ pstore_register() */
+ if (!psinfo || !spin_trylock(&pstore_lock))
+ return;
+ break;
+ default:
+ mutex_lock(&psinfo->buf_mutex);
+ }
+
oopscount++;
while (total < kmsg_bytes) {
dst = psinfo->buf;
@@ -103,7 +113,20 @@ static void pstore_dump(struct kmsg_dumper *dumper,
l2 -= l2_cpy;
total += l1_cpy + l2_cpy;
}
- mutex_unlock(&psinfo->buf_mutex);
+
+ if (reason != KMSG_DUMP_KEXEC)
+ mutex_unlock(&psinfo->buf_mutex);
+}
+
+void pstore_kmsg_dump_in_interrupt(enum kmsg_dump_reason reason)
+{
+ const char *s1, *s2;
+ unsigned long l1, l2;
+
+ /* get logbuf values without spin_lock for avoiding dead lock */
+ get_logbuf_nolock(&s1, &l1, &s2, &l2);
+
+ pstore_dump(NULL, reason, s1, l1, s2, l2);
}
static struct kmsg_dumper pstore_dumper = {
diff --git a/include/linux/kmsg_dump.h b/include/linux/kmsg_dump.h
index fee6631..ee0c952 100644
--- a/include/linux/kmsg_dump.h
+++ b/include/linux/kmsg_dump.h
@@ -18,6 +18,7 @@
enum kmsg_dump_reason {
KMSG_DUMP_OOPS,
KMSG_DUMP_PANIC,
+ KMSG_DUMP_KEXEC,
KMSG_DUMP_RESTART,
KMSG_DUMP_HALT,
KMSG_DUMP_POWEROFF,
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index 2455ef2..5cf008d 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -22,6 +22,8 @@
#ifndef _LINUX_PSTORE_H
#define _LINUX_PSTORE_H
+#include<linux/kmsg_dump.h>
+
/* types */
enum pstore_type_id {
PSTORE_TYPE_DMESG = 0,
@@ -46,6 +48,9 @@ struct pstore_info {
#ifdef CONFIG_PSTORE
extern int pstore_register(struct pstore_info *);
extern int pstore_write(enum pstore_type_id type, char *buf, size_t size);
+extern void pstore_kmsg_dump_in_interrupt(enum kmsg_dump_reason reason);
+extern void get_logbuf_nolock(const char **s1, unsigned long *l1,
+ const char **s2, unsigned long *l2);
#else
static inline int
pstore_register(struct pstore_info *psi)
@@ -57,6 +62,10 @@ pstore_write(enum pstore_type_id type, char *buf, size_t size)
{
return -ENODEV;
}
+static inline void
+pstore_kmsg_dump_in_interrupt(enum kmsg_dump_reason reason)
+{
+}
#endif
#endif /*_LINUX_PSTORE_H*/
diff --git a/kernel/kexec.c b/kernel/kexec.c
index e24bc1b..8e2761a 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -33,6 +33,8 @@
#include <linux/vmalloc.h>
#include <linux/swap.h>
#include <linux/syscore_ops.h>
+#include <linux/kmsg_dump.h>
+#include <linux/pstore.h>
#include <asm/page.h>
#include <asm/uaccess.h>
@@ -1081,6 +1083,7 @@ void crash_kexec(struct pt_regs *regs)
crash_setup_regs(&fixed_regs, regs);
crash_save_vmcoreinfo();
machine_crash_shutdown(&fixed_regs);
+ pstore_kmsg_dump_in_interrupt(KMSG_DUMP_KEXEC);
machine_kexec(kexec_crash_image);
}
mutex_unlock(&kexec_mutex);
diff --git a/kernel/printk.c b/kernel/printk.c
index 37dff34..966a7d9 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -1710,6 +1710,35 @@ int kmsg_dump_unregister(struct kmsg_dumper *dumper)
}
EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
+
+void get_logbuf_nolock(const char **s1, unsigned long *l1, const char **s2,
+ unsigned long *l2)
+{
+ unsigned long end;
+ unsigned chars;
+
+ /* Theoretically, the log could move on after we do this, but
+ there's not a lot we can do about that. The new messages
+ will overwrite the start of what we dump. */
+ end = log_end & LOG_BUF_MASK;
+ chars = logged_chars;
+
+ if (chars > end) {
+ *s1 = log_buf + log_buf_len - chars + end;
+ *l1 = chars - end;
+
+ *s2 = log_buf;
+ *l2 = end;
+ } else {
+ *s1 = "";
+ *l1 = 0;
+
+ *s2 = log_buf + end - chars;
+ *l2 = chars;
+ }
+
+}
+
/**
* kmsg_dump - dump kernel log to kernel message dumpers.
* @reason: the reason (oops, panic etc) for dumping
--
1.7.1
More information about the kexec
mailing list