Root/target/linux/generic-2.6/patches-2.6.30/930-kmsg_dump_backport.patch

1--- /dev/null
2+++ b/include/linux/kmsg_dump.h
3@@ -0,0 +1,44 @@
4+/*
5+ * linux/include/kmsg_dump.h
6+ *
7+ * Copyright (C) 2009 Net Insight AB
8+ *
9+ * Author: Simon Kagstrom <simon.kagstrom@netinsight.net>
10+ *
11+ * This file is subject to the terms and conditions of the GNU General Public
12+ * License. See the file COPYING in the main directory of this archive
13+ * for more details.
14+ */
15+#ifndef _LINUX_KMSG_DUMP_H
16+#define _LINUX_KMSG_DUMP_H
17+
18+#include <linux/list.h>
19+
20+enum kmsg_dump_reason {
21+ KMSG_DUMP_OOPS,
22+ KMSG_DUMP_PANIC,
23+};
24+
25+/**
26+ * struct kmsg_dumper - kernel crash message dumper structure
27+ * @dump: The callback which gets called on crashes. The buffer is passed
28+ * as two sections, where s1 (length l1) contains the older
29+ * messages and s2 (length l2) contains the newer.
30+ * @list: Entry in the dumper list (private)
31+ * @registered: Flag that specifies if this is already registered
32+ */
33+struct kmsg_dumper {
34+ void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
35+ const char *s1, unsigned long l1,
36+ const char *s2, unsigned long l2);
37+ struct list_head list;
38+ int registered;
39+};
40+
41+void kmsg_dump(enum kmsg_dump_reason reason);
42+
43+int kmsg_dump_register(struct kmsg_dumper *dumper);
44+
45+int kmsg_dump_unregister(struct kmsg_dumper *dumper);
46+
47+#endif /* _LINUX_KMSG_DUMP_H */
48--- a/kernel/panic.c
49+++ b/kernel/panic.c
50@@ -10,6 +10,7 @@
51  */
52 #include <linux/debug_locks.h>
53 #include <linux/interrupt.h>
54+#include <linux/kmsg_dump.h>
55 #include <linux/kallsyms.h>
56 #include <linux/notifier.h>
57 #include <linux/module.h>
58@@ -74,6 +75,7 @@ NORET_TYPE void panic(const char * fmt,
59     dump_stack();
60 #endif
61 
62+ kmsg_dump(KMSG_DUMP_PANIC);
63     /*
64      * If we have crashed and we have a crash kernel loaded let it handle
65      * everything else.
66@@ -337,6 +339,7 @@ void oops_exit(void)
67 {
68     do_oops_enter_exit();
69     print_oops_end_marker();
70+ kmsg_dump(KMSG_DUMP_OOPS);
71 }
72 
73 #ifdef WANT_WARN_ON_SLOWPATH
74--- a/kernel/printk.c
75+++ b/kernel/printk.c
76@@ -33,6 +33,7 @@
77 #include <linux/bootmem.h>
78 #include <linux/syscalls.h>
79 #include <linux/kexec.h>
80+#include <linux/kmsg_dump.h>
81 
82 #include <asm/uaccess.h>
83 
84@@ -1322,3 +1323,121 @@ bool printk_timed_ratelimit(unsigned lon
85 }
86 EXPORT_SYMBOL(printk_timed_ratelimit);
87 #endif
88+
89+static DEFINE_SPINLOCK(dump_list_lock);
90+static LIST_HEAD(dump_list);
91+
92+/**
93+ * kmsg_dump_register - register a kernel log dumper.
94+ * @dump: pointer to the kmsg_dumper structure
95+ *
96+ * Adds a kernel log dumper to the system. The dump callback in the
97+ * structure will be called when the kernel oopses or panics and must be
98+ * set. Returns zero on success and %-EINVAL or %-EBUSY otherwise.
99+ */
100+int kmsg_dump_register(struct kmsg_dumper *dumper)
101+{
102+ unsigned long flags;
103+ int err = -EBUSY;
104+
105+ /* The dump callback needs to be set */
106+ if (!dumper->dump)
107+ return -EINVAL;
108+
109+ spin_lock_irqsave(&dump_list_lock, flags);
110+ /* Don't allow registering multiple times */
111+ if (!dumper->registered) {
112+ dumper->registered = 1;
113+ list_add_tail(&dumper->list, &dump_list);
114+ err = 0;
115+ }
116+ spin_unlock_irqrestore(&dump_list_lock, flags);
117+
118+ return err;
119+}
120+EXPORT_SYMBOL_GPL(kmsg_dump_register);
121+
122+/**
123+ * kmsg_dump_unregister - unregister a kmsg dumper.
124+ * @dump: pointer to the kmsg_dumper structure
125+ *
126+ * Removes a dump device from the system. Returns zero on success and
127+ * %-EINVAL otherwise.
128+ */
129+int kmsg_dump_unregister(struct kmsg_dumper *dumper)
130+{
131+ unsigned long flags;
132+ int err = -EINVAL;
133+
134+ spin_lock_irqsave(&dump_list_lock, flags);
135+ if (dumper->registered) {
136+ dumper->registered = 0;
137+ list_del(&dumper->list);
138+ err = 0;
139+ }
140+ spin_unlock_irqrestore(&dump_list_lock, flags);
141+
142+ return err;
143+}
144+EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
145+
146+static const char const *kmsg_reasons[] = {
147+ [KMSG_DUMP_OOPS] = "oops",
148+ [KMSG_DUMP_PANIC] = "panic",
149+};
150+
151+static const char *kmsg_to_str(enum kmsg_dump_reason reason)
152+{
153+ if (reason >= ARRAY_SIZE(kmsg_reasons) || reason < 0)
154+ return "unknown";
155+
156+ return kmsg_reasons[reason];
157+}
158+
159+/**
160+ * kmsg_dump - dump kernel log to kernel message dumpers.
161+ * @reason: the reason (oops, panic etc) for dumping
162+ *
163+ * Iterate through each of the dump devices and call the oops/panic
164+ * callbacks with the log buffer.
165+ */
166+void kmsg_dump(enum kmsg_dump_reason reason)
167+{
168+ unsigned long end;
169+ unsigned chars;
170+ struct kmsg_dumper *dumper;
171+ const char *s1, *s2;
172+ unsigned long l1, l2;
173+ unsigned long flags;
174+
175+ /* Theoretically, the log could move on after we do this, but
176+ there's not a lot we can do about that. The new messages
177+ will overwrite the start of what we dump. */
178+ spin_lock_irqsave(&logbuf_lock, flags);
179+ end = log_end & LOG_BUF_MASK;
180+ chars = logged_chars;
181+ spin_unlock_irqrestore(&logbuf_lock, flags);
182+
183+ if (logged_chars > end) {
184+ s1 = log_buf + log_buf_len - logged_chars + end;
185+ l1 = logged_chars - end;
186+
187+ s2 = log_buf;
188+ l2 = end;
189+ } else {
190+ s1 = "";
191+ l1 = 0;
192+
193+ s2 = log_buf + end - logged_chars;
194+ l2 = logged_chars;
195+ }
196+
197+ if (!spin_trylock_irqsave(&dump_list_lock, flags)) {
198+ printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n",
199+ kmsg_to_str(reason));
200+ return;
201+ }
202+ list_for_each_entry(dumper, &dump_list, list)
203+ dumper->dump(dumper, reason, s1, l1, s2, l2);
204+ spin_unlock_irqrestore(&dump_list_lock, flags);
205+}
206

Archive Download this file



interactive