aboutsummaryrefslogtreecommitdiffstats
path: root/fs/pstore
diff options
context:
space:
mode:
authorAnton Vorontsov <anton.vorontsov@linaro.org>2012-05-16 08:43:08 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-05-16 11:06:37 -0400
commit1894a253db97059bc299b834b76f665bc6586b1d (patch)
tree791ad2d33cc1d28c32fa340b0a8f0c2a645c4b26 /fs/pstore
parentd109a674a3685d43f16da5cc4cb8b927d07c436d (diff)
ramoops: Move to fs/pstore/ram.c
Since ramoops was converted to pstore, it has nothing to do with character devices nowadays. Instead, today it is just a RAM backend for pstore. The patch just moves things around. There are a few changes were needed because of the move: 1. Kconfig and Makefiles fixups, of course. 2. In pstore/ram.c we have to play a bit with MODULE_PARAM_PREFIX, this is needed to keep user experience the same as with ramoops driver (i.e. so that ramoops.foo kernel command line arguments would still work). Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org> Acked-by: Marco Stornelli <marco.stornelli@gmail.com> Acked-by: Kees Cook <keescook@chromium.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/pstore')
-rw-r--r--fs/pstore/Kconfig14
-rw-r--r--fs/pstore/Makefile3
-rw-r--r--fs/pstore/ram.c362
3 files changed, 379 insertions, 0 deletions
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 8007ae7c0d8..b75ee51b271 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -11,3 +11,17 @@ config PSTORE
11 (e.g. ACPI_APEI on X86) which will select this for you. 11 (e.g. ACPI_APEI on X86) which will select this for you.
12 If you don't have a platform persistent store driver, 12 If you don't have a platform persistent store driver,
13 say N. 13 say N.
14
15config PSTORE_RAM
16 tristate "Log panic/oops to a RAM buffer"
17 depends on HAS_IOMEM
18 depends on PSTORE
19 default n
20 help
21 This enables panic and oops messages to be logged to a circular
22 buffer in RAM where it can be read back at some later point.
23
24 Note that for historical reasons, the module will be named
25 "ramoops.ko".
26
27 For more information, see Documentation/ramoops.txt.
diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile
index 760f4bce7d1..2ab3d0d55ef 100644
--- a/fs/pstore/Makefile
+++ b/fs/pstore/Makefile
@@ -5,3 +5,6 @@
5obj-y += pstore.o 5obj-y += pstore.o
6 6
7pstore-objs += inode.o platform.o 7pstore-objs += inode.o platform.o
8
9ramoops-objs += ram.o
10obj-$(CONFIG_PSTORE_RAM) += ramoops.o
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
new file mode 100644
index 00000000000..e443c9c6914
--- /dev/null
+++ b/fs/pstore/ram.c
@@ -0,0 +1,362 @@
1/*
2 * RAM Oops/Panic logger
3 *
4 * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
5 * Copyright (C) 2011 Kees Cook <keescook@chromium.org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 *
21 */
22
23#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24
25#include <linux/kernel.h>
26#include <linux/err.h>
27#include <linux/module.h>
28#include <linux/pstore.h>
29#include <linux/time.h>
30#include <linux/io.h>
31#include <linux/ioport.h>
32#include <linux/platform_device.h>
33#include <linux/slab.h>
34#include <linux/pstore_ram.h>
35
36#define RAMOOPS_KERNMSG_HDR "===="
37#define MIN_MEM_SIZE 4096UL
38
39static ulong record_size = MIN_MEM_SIZE;
40module_param(record_size, ulong, 0400);
41MODULE_PARM_DESC(record_size,
42 "size of each dump done on oops/panic");
43
44static ulong mem_address;
45module_param(mem_address, ulong, 0400);
46MODULE_PARM_DESC(mem_address,
47 "start of reserved RAM used to store oops/panic logs");
48
49static ulong mem_size;
50module_param(mem_size, ulong, 0400);
51MODULE_PARM_DESC(mem_size,
52 "size of reserved RAM used to store oops/panic logs");
53
54static int dump_oops = 1;
55module_param(dump_oops, int, 0600);
56MODULE_PARM_DESC(dump_oops,
57 "set to 1 to dump oopses, 0 to only dump panics (default 1)");
58
59struct ramoops_context {
60 void *virt_addr;
61 phys_addr_t phys_addr;
62 unsigned long size;
63 size_t record_size;
64 int dump_oops;
65 unsigned int count;
66 unsigned int max_count;
67 unsigned int read_count;
68 struct pstore_info pstore;
69};
70
71static struct platform_device *dummy;
72static struct ramoops_platform_data *dummy_data;
73
74static int ramoops_pstore_open(struct pstore_info *psi)
75{
76 struct ramoops_context *cxt = psi->data;
77
78 cxt->read_count = 0;
79 return 0;
80}
81
82static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
83 struct timespec *time,
84 char **buf,
85 struct pstore_info *psi)
86{
87 ssize_t size;
88 char *rambuf;
89 struct ramoops_context *cxt = psi->data;
90
91 if (cxt->read_count >= cxt->max_count)
92 return -EINVAL;
93 *id = cxt->read_count++;
94 /* Only supports dmesg output so far. */
95 *type = PSTORE_TYPE_DMESG;
96 /* TODO(kees): Bogus time for the moment. */
97 time->tv_sec = 0;
98 time->tv_nsec = 0;
99
100 rambuf = cxt->virt_addr + (*id * cxt->record_size);
101 size = strnlen(rambuf, cxt->record_size);
102 *buf = kmalloc(size, GFP_KERNEL);
103 if (*buf == NULL)
104 return -ENOMEM;
105 memcpy(*buf, rambuf, size);
106
107 return size;
108}
109
110static int ramoops_pstore_write(enum pstore_type_id type,
111 enum kmsg_dump_reason reason,
112 u64 *id,
113 unsigned int part,
114 size_t size, struct pstore_info *psi)
115{
116 char *buf;
117 size_t res;
118 struct timeval timestamp;
119 struct ramoops_context *cxt = psi->data;
120 size_t available = cxt->record_size;
121
122 /* Currently ramoops is designed to only store dmesg dumps. */
123 if (type != PSTORE_TYPE_DMESG)
124 return -EINVAL;
125
126 /* Out of the various dmesg dump types, ramoops is currently designed
127 * to only store crash logs, rather than storing general kernel logs.
128 */
129 if (reason != KMSG_DUMP_OOPS &&
130 reason != KMSG_DUMP_PANIC)
131 return -EINVAL;
132
133 /* Skip Oopes when configured to do so. */
134 if (reason == KMSG_DUMP_OOPS && !cxt->dump_oops)
135 return -EINVAL;
136
137 /* Explicitly only take the first part of any new crash.
138 * If our buffer is larger than kmsg_bytes, this can never happen,
139 * and if our buffer is smaller than kmsg_bytes, we don't want the
140 * report split across multiple records.
141 */
142 if (part != 1)
143 return -ENOSPC;
144
145 buf = cxt->virt_addr + (cxt->count * cxt->record_size);
146
147 res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR);
148 buf += res;
149 available -= res;
150
151 do_gettimeofday(&timestamp);
152 res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec);
153 buf += res;
154 available -= res;
155
156 if (size > available)
157 size = available;
158
159 memcpy(buf, cxt->pstore.buf, size);
160 memset(buf + size, '\0', available - size);
161
162 cxt->count = (cxt->count + 1) % cxt->max_count;
163
164 return 0;
165}
166
167static int ramoops_pstore_erase(enum pstore_type_id type, u64 id,
168 struct pstore_info *psi)
169{
170 char *buf;
171 struct ramoops_context *cxt = psi->data;
172
173 if (id >= cxt->max_count)
174 return -EINVAL;
175
176 buf = cxt->virt_addr + (id * cxt->record_size);
177 memset(buf, '\0', cxt->record_size);
178
179 return 0;
180}
181
182static struct ramoops_context oops_cxt = {
183 .pstore = {
184 .owner = THIS_MODULE,
185 .name = "ramoops",
186 .open = ramoops_pstore_open,
187 .read = ramoops_pstore_read,
188 .write = ramoops_pstore_write,
189 .erase = ramoops_pstore_erase,
190 },
191};
192
193static int __init ramoops_probe(struct platform_device *pdev)
194{
195 struct ramoops_platform_data *pdata = pdev->dev.platform_data;
196 struct ramoops_context *cxt = &oops_cxt;
197 int err = -EINVAL;
198
199 /* Only a single ramoops area allowed at a time, so fail extra
200 * probes.
201 */
202 if (cxt->max_count)
203 goto fail_out;
204
205 if (!pdata->mem_size || !pdata->record_size) {
206 pr_err("The memory size and the record size must be "
207 "non-zero\n");
208 goto fail_out;
209 }
210
211 pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
212 pdata->record_size = rounddown_pow_of_two(pdata->record_size);
213
214 /* Check for the minimum memory size */
215 if (pdata->mem_size < MIN_MEM_SIZE &&
216 pdata->record_size < MIN_MEM_SIZE) {
217 pr_err("memory size too small, minimum is %lu\n",
218 MIN_MEM_SIZE);
219 goto fail_out;
220 }
221
222 if (pdata->mem_size < pdata->record_size) {
223 pr_err("The memory size must be larger than the "
224 "records size\n");
225 goto fail_out;
226 }
227
228 cxt->max_count = pdata->mem_size / pdata->record_size;
229 cxt->count = 0;
230 cxt->size = pdata->mem_size;
231 cxt->phys_addr = pdata->mem_address;
232 cxt->record_size = pdata->record_size;
233 cxt->dump_oops = pdata->dump_oops;
234
235 cxt->pstore.data = cxt;
236 cxt->pstore.bufsize = cxt->record_size;
237 cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL);
238 spin_lock_init(&cxt->pstore.buf_lock);
239 if (!cxt->pstore.buf) {
240 pr_err("cannot allocate pstore buffer\n");
241 goto fail_clear;
242 }
243
244 if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) {
245 pr_err("request mem region (0x%lx@0x%llx) failed\n",
246 cxt->size, (unsigned long long)cxt->phys_addr);
247 err = -EINVAL;
248 goto fail_buf;
249 }
250
251 cxt->virt_addr = ioremap(cxt->phys_addr, cxt->size);
252 if (!cxt->virt_addr) {
253 pr_err("ioremap failed\n");
254 goto fail_mem_region;
255 }
256
257 err = pstore_register(&cxt->pstore);
258 if (err) {
259 pr_err("registering with pstore failed\n");
260 goto fail_iounmap;
261 }
262
263 /*
264 * Update the module parameter variables as well so they are visible
265 * through /sys/module/ramoops/parameters/
266 */
267 mem_size = pdata->mem_size;
268 mem_address = pdata->mem_address;
269 record_size = pdata->record_size;
270 dump_oops = pdata->dump_oops;
271
272 pr_info("attached 0x%lx@0x%llx (%ux0x%zx)\n",
273 cxt->size, (unsigned long long)cxt->phys_addr,
274 cxt->max_count, cxt->record_size);
275
276 return 0;
277
278fail_iounmap:
279 iounmap(cxt->virt_addr);
280fail_mem_region:
281 release_mem_region(cxt->phys_addr, cxt->size);
282fail_buf:
283 kfree(cxt->pstore.buf);
284fail_clear:
285 cxt->pstore.bufsize = 0;
286 cxt->max_count = 0;
287fail_out:
288 return err;
289}
290
291static int __exit ramoops_remove(struct platform_device *pdev)
292{
293#if 0
294 /* TODO(kees): We cannot unload ramoops since pstore doesn't support
295 * unregistering yet.
296 */
297 struct ramoops_context *cxt = &oops_cxt;
298
299 iounmap(cxt->virt_addr);
300 release_mem_region(cxt->phys_addr, cxt->size);
301 cxt->max_count = 0;
302
303 /* TODO(kees): When pstore supports unregistering, call it here. */
304 kfree(cxt->pstore.buf);
305 cxt->pstore.bufsize = 0;
306
307 return 0;
308#endif
309 return -EBUSY;
310}
311
312static struct platform_driver ramoops_driver = {
313 .remove = __exit_p(ramoops_remove),
314 .driver = {
315 .name = "ramoops",
316 .owner = THIS_MODULE,
317 },
318};
319
320static int __init ramoops_init(void)
321{
322 int ret;
323 ret = platform_driver_probe(&ramoops_driver, ramoops_probe);
324 if (ret == -ENODEV) {
325 /*
326 * If we didn't find a platform device, we use module parameters
327 * building platform data on the fly.
328 */
329 pr_info("platform device not found, using module parameters\n");
330 dummy_data = kzalloc(sizeof(struct ramoops_platform_data),
331 GFP_KERNEL);
332 if (!dummy_data)
333 return -ENOMEM;
334 dummy_data->mem_size = mem_size;
335 dummy_data->mem_address = mem_address;
336 dummy_data->record_size = record_size;
337 dummy_data->dump_oops = dump_oops;
338 dummy = platform_create_bundle(&ramoops_driver, ramoops_probe,
339 NULL, 0, dummy_data,
340 sizeof(struct ramoops_platform_data));
341
342 if (IS_ERR(dummy))
343 ret = PTR_ERR(dummy);
344 else
345 ret = 0;
346 }
347
348 return ret;
349}
350
351static void __exit ramoops_exit(void)
352{
353 platform_driver_unregister(&ramoops_driver);
354 kfree(dummy_data);
355}
356
357module_init(ramoops_init);
358module_exit(ramoops_exit);
359
360MODULE_LICENSE("GPL");
361MODULE_AUTHOR("Marco Stornelli <marco.stornelli@gmail.com>");
362MODULE_DESCRIPTION("RAM Oops/Panic logger/driver");