aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/pstore/Kconfig10
-rw-r--r--fs/pstore/Makefile2
-rw-r--r--fs/pstore/inode.c3
-rw-r--r--fs/pstore/internal.h6
-rw-r--r--fs/pstore/platform.c1
-rw-r--r--fs/pstore/pmsg.c114
-rw-r--r--fs/pstore/ram.c34
-rw-r--r--include/linux/pstore.h1
-rw-r--r--include/linux/pstore_ram.h1
9 files changed, 170 insertions, 2 deletions
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 983d9510becc..916b8e23d968 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -21,6 +21,16 @@ config PSTORE_CONSOLE
21 When the option is enabled, pstore will log all kernel 21 When the option is enabled, pstore will log all kernel
22 messages, even if no oops or panic happened. 22 messages, even if no oops or panic happened.
23 23
24config PSTORE_PMSG
25 bool "Log user space messages"
26 depends on PSTORE
27 help
28 When the option is enabled, pstore will export a character
29 interface /dev/pmsg0 to log user space messages. On reboot
30 data can be retrieved from /sys/fs/pstore/pmsg-ramoops-[ID].
31
32 If unsure, say N.
33
24config PSTORE_FTRACE 34config PSTORE_FTRACE
25 bool "Persistent function tracer" 35 bool "Persistent function tracer"
26 depends on PSTORE 36 depends on PSTORE
diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile
index 4c9095c2781e..e647d8e81712 100644
--- a/fs/pstore/Makefile
+++ b/fs/pstore/Makefile
@@ -7,5 +7,7 @@ obj-y += pstore.o
7pstore-objs += inode.o platform.o 7pstore-objs += inode.o platform.o
8obj-$(CONFIG_PSTORE_FTRACE) += ftrace.o 8obj-$(CONFIG_PSTORE_FTRACE) += ftrace.o
9 9
10obj-$(CONFIG_PSTORE_PMSG) += pmsg.o
11
10ramoops-objs += ram.o ram_core.o 12ramoops-objs += ram.o ram_core.o
11obj-$(CONFIG_PSTORE_RAM) += ramoops.o 13obj-$(CONFIG_PSTORE_RAM) += ramoops.o
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index d69586f09ffd..b32ce53d24ee 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -361,6 +361,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
361 scnprintf(name, sizeof(name), "powerpc-common-%s-%lld", 361 scnprintf(name, sizeof(name), "powerpc-common-%s-%lld",
362 psname, id); 362 psname, id);
363 break; 363 break;
364 case PSTORE_TYPE_PMSG:
365 scnprintf(name, sizeof(name), "pmsg-%s-%lld", psname, id);
366 break;
364 case PSTORE_TYPE_UNKNOWN: 367 case PSTORE_TYPE_UNKNOWN:
365 scnprintf(name, sizeof(name), "unknown-%s-%lld", psname, id); 368 scnprintf(name, sizeof(name), "unknown-%s-%lld", psname, id);
366 break; 369 break;
diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
index 3b3d305277c4..c36ba2cd0b5d 100644
--- a/fs/pstore/internal.h
+++ b/fs/pstore/internal.h
@@ -45,6 +45,12 @@ extern void pstore_register_ftrace(void);
45static inline void pstore_register_ftrace(void) {} 45static inline void pstore_register_ftrace(void) {}
46#endif 46#endif
47 47
48#ifdef CONFIG_PSTORE_PMSG
49extern void pstore_register_pmsg(void);
50#else
51static inline void pstore_register_pmsg(void) {}
52#endif
53
48extern struct pstore_info *psinfo; 54extern struct pstore_info *psinfo;
49 55
50extern void pstore_set_kmsg_bytes(int); 56extern void pstore_set_kmsg_bytes(int);
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 0a9b72cdfeca..15ee78c5020b 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -447,6 +447,7 @@ int pstore_register(struct pstore_info *psi)
447 if ((psi->flags & PSTORE_FLAGS_FRAGILE) == 0) { 447 if ((psi->flags & PSTORE_FLAGS_FRAGILE) == 0) {
448 pstore_register_console(); 448 pstore_register_console();
449 pstore_register_ftrace(); 449 pstore_register_ftrace();
450 pstore_register_pmsg();
450 } 451 }
451 452
452 if (pstore_update_ms >= 0) { 453 if (pstore_update_ms >= 0) {
diff --git a/fs/pstore/pmsg.c b/fs/pstore/pmsg.c
new file mode 100644
index 000000000000..feb5dd2948b4
--- /dev/null
+++ b/fs/pstore/pmsg.c
@@ -0,0 +1,114 @@
1/*
2 * Copyright 2014 Google, Inc.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/cdev.h>
15#include <linux/device.h>
16#include <linux/fs.h>
17#include <linux/uaccess.h>
18#include <linux/vmalloc.h>
19#include "internal.h"
20
21static DEFINE_MUTEX(pmsg_lock);
22#define PMSG_MAX_BOUNCE_BUFFER_SIZE (2*PAGE_SIZE)
23
24static ssize_t write_pmsg(struct file *file, const char __user *buf,
25 size_t count, loff_t *ppos)
26{
27 size_t i, buffer_size;
28 char *buffer;
29
30 if (!count)
31 return 0;
32
33 if (!access_ok(VERIFY_READ, buf, count))
34 return -EFAULT;
35
36 buffer_size = count;
37 if (buffer_size > PMSG_MAX_BOUNCE_BUFFER_SIZE)
38 buffer_size = PMSG_MAX_BOUNCE_BUFFER_SIZE;
39 buffer = vmalloc(buffer_size);
40
41 mutex_lock(&pmsg_lock);
42 for (i = 0; i < count; ) {
43 size_t c = min(count - i, buffer_size);
44 u64 id;
45 long ret;
46
47 ret = __copy_from_user(buffer, buf + i, c);
48 if (unlikely(ret != 0)) {
49 mutex_unlock(&pmsg_lock);
50 vfree(buffer);
51 return -EFAULT;
52 }
53 psinfo->write_buf(PSTORE_TYPE_PMSG, 0, &id, 0, buffer, 0, c,
54 psinfo);
55
56 i += c;
57 }
58
59 mutex_unlock(&pmsg_lock);
60 vfree(buffer);
61 return count;
62}
63
64static const struct file_operations pmsg_fops = {
65 .owner = THIS_MODULE,
66 .llseek = noop_llseek,
67 .write = write_pmsg,
68};
69
70static struct class *pmsg_class;
71static int pmsg_major;
72#define PMSG_NAME "pmsg"
73#undef pr_fmt
74#define pr_fmt(fmt) PMSG_NAME ": " fmt
75
76static char *pmsg_devnode(struct device *dev, umode_t *mode)
77{
78 if (mode)
79 *mode = 0220;
80 return NULL;
81}
82
83void pstore_register_pmsg(void)
84{
85 struct device *pmsg_device;
86
87 pmsg_major = register_chrdev(0, PMSG_NAME, &pmsg_fops);
88 if (pmsg_major < 0) {
89 pr_err("register_chrdev failed\n");
90 goto err;
91 }
92
93 pmsg_class = class_create(THIS_MODULE, PMSG_NAME);
94 if (IS_ERR(pmsg_class)) {
95 pr_err("device class file already in use\n");
96 goto err_class;
97 }
98 pmsg_class->devnode = pmsg_devnode;
99
100 pmsg_device = device_create(pmsg_class, NULL, MKDEV(pmsg_major, 0),
101 NULL, "%s%d", PMSG_NAME, 0);
102 if (IS_ERR(pmsg_device)) {
103 pr_err("failed to create device\n");
104 goto err_device;
105 }
106 return;
107
108err_device:
109 class_destroy(pmsg_class);
110err_class:
111 unregister_chrdev(pmsg_major, PMSG_NAME);
112err:
113 return;
114}
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 6150e54eed30..39d1373128e9 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -51,6 +51,10 @@ static ulong ramoops_ftrace_size = MIN_MEM_SIZE;
51module_param_named(ftrace_size, ramoops_ftrace_size, ulong, 0400); 51module_param_named(ftrace_size, ramoops_ftrace_size, ulong, 0400);
52MODULE_PARM_DESC(ftrace_size, "size of ftrace log"); 52MODULE_PARM_DESC(ftrace_size, "size of ftrace log");
53 53
54static ulong ramoops_pmsg_size = MIN_MEM_SIZE;
55module_param_named(pmsg_size, ramoops_pmsg_size, ulong, 0400);
56MODULE_PARM_DESC(pmsg_size, "size of user space message log");
57
54static ulong mem_address; 58static ulong mem_address;
55module_param(mem_address, ulong, 0400); 59module_param(mem_address, ulong, 0400);
56MODULE_PARM_DESC(mem_address, 60MODULE_PARM_DESC(mem_address,
@@ -82,12 +86,14 @@ struct ramoops_context {
82 struct persistent_ram_zone **przs; 86 struct persistent_ram_zone **przs;
83 struct persistent_ram_zone *cprz; 87 struct persistent_ram_zone *cprz;
84 struct persistent_ram_zone *fprz; 88 struct persistent_ram_zone *fprz;
89 struct persistent_ram_zone *mprz;
85 phys_addr_t phys_addr; 90 phys_addr_t phys_addr;
86 unsigned long size; 91 unsigned long size;
87 unsigned int memtype; 92 unsigned int memtype;
88 size_t record_size; 93 size_t record_size;
89 size_t console_size; 94 size_t console_size;
90 size_t ftrace_size; 95 size_t ftrace_size;
96 size_t pmsg_size;
91 int dump_oops; 97 int dump_oops;
92 struct persistent_ram_ecc_info ecc_info; 98 struct persistent_ram_ecc_info ecc_info;
93 unsigned int max_dump_cnt; 99 unsigned int max_dump_cnt;
@@ -96,6 +102,7 @@ struct ramoops_context {
96 unsigned int dump_read_cnt; 102 unsigned int dump_read_cnt;
97 unsigned int console_read_cnt; 103 unsigned int console_read_cnt;
98 unsigned int ftrace_read_cnt; 104 unsigned int ftrace_read_cnt;
105 unsigned int pmsg_read_cnt;
99 struct pstore_info pstore; 106 struct pstore_info pstore;
100}; 107};
101 108
@@ -109,6 +116,7 @@ static int ramoops_pstore_open(struct pstore_info *psi)
109 cxt->dump_read_cnt = 0; 116 cxt->dump_read_cnt = 0;
110 cxt->console_read_cnt = 0; 117 cxt->console_read_cnt = 0;
111 cxt->ftrace_read_cnt = 0; 118 cxt->ftrace_read_cnt = 0;
119 cxt->pmsg_read_cnt = 0;
112 return 0; 120 return 0;
113} 121}
114 122
@@ -191,6 +199,9 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
191 prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt, 199 prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
192 1, id, type, PSTORE_TYPE_FTRACE, 0); 200 1, id, type, PSTORE_TYPE_FTRACE, 0);
193 if (!prz_ok(prz)) 201 if (!prz_ok(prz))
202 prz = ramoops_get_next_prz(&cxt->mprz, &cxt->pmsg_read_cnt,
203 1, id, type, PSTORE_TYPE_PMSG, 0);
204 if (!prz_ok(prz))
194 return 0; 205 return 0;
195 206
196 if (!persistent_ram_old(prz)) 207 if (!persistent_ram_old(prz))
@@ -258,6 +269,11 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
258 return -ENOMEM; 269 return -ENOMEM;
259 persistent_ram_write(cxt->fprz, buf, size); 270 persistent_ram_write(cxt->fprz, buf, size);
260 return 0; 271 return 0;
272 } else if (type == PSTORE_TYPE_PMSG) {
273 if (!cxt->mprz)
274 return -ENOMEM;
275 persistent_ram_write(cxt->mprz, buf, size);
276 return 0;
261 } 277 }
262 278
263 if (type != PSTORE_TYPE_DMESG) 279 if (type != PSTORE_TYPE_DMESG)
@@ -315,6 +331,9 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count,
315 case PSTORE_TYPE_FTRACE: 331 case PSTORE_TYPE_FTRACE:
316 prz = cxt->fprz; 332 prz = cxt->fprz;
317 break; 333 break;
334 case PSTORE_TYPE_PMSG:
335 prz = cxt->mprz;
336 break;
318 default: 337 default:
319 return -EINVAL; 338 return -EINVAL;
320 } 339 }
@@ -441,7 +460,7 @@ static int ramoops_probe(struct platform_device *pdev)
441 goto fail_out; 460 goto fail_out;
442 461
443 if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size && 462 if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size &&
444 !pdata->ftrace_size)) { 463 !pdata->ftrace_size && !pdata->pmsg_size)) {
445 pr_err("The memory size and the record/console size must be " 464 pr_err("The memory size and the record/console size must be "
446 "non-zero\n"); 465 "non-zero\n");
447 goto fail_out; 466 goto fail_out;
@@ -453,6 +472,8 @@ static int ramoops_probe(struct platform_device *pdev)
453 pdata->console_size = rounddown_pow_of_two(pdata->console_size); 472 pdata->console_size = rounddown_pow_of_two(pdata->console_size);
454 if (pdata->ftrace_size && !is_power_of_2(pdata->ftrace_size)) 473 if (pdata->ftrace_size && !is_power_of_2(pdata->ftrace_size))
455 pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size); 474 pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size);
475 if (pdata->pmsg_size && !is_power_of_2(pdata->pmsg_size))
476 pdata->pmsg_size = rounddown_pow_of_two(pdata->pmsg_size);
456 477
457 cxt->size = pdata->mem_size; 478 cxt->size = pdata->mem_size;
458 cxt->phys_addr = pdata->mem_address; 479 cxt->phys_addr = pdata->mem_address;
@@ -460,12 +481,14 @@ static int ramoops_probe(struct platform_device *pdev)
460 cxt->record_size = pdata->record_size; 481 cxt->record_size = pdata->record_size;
461 cxt->console_size = pdata->console_size; 482 cxt->console_size = pdata->console_size;
462 cxt->ftrace_size = pdata->ftrace_size; 483 cxt->ftrace_size = pdata->ftrace_size;
484 cxt->pmsg_size = pdata->pmsg_size;
463 cxt->dump_oops = pdata->dump_oops; 485 cxt->dump_oops = pdata->dump_oops;
464 cxt->ecc_info = pdata->ecc_info; 486 cxt->ecc_info = pdata->ecc_info;
465 487
466 paddr = cxt->phys_addr; 488 paddr = cxt->phys_addr;
467 489
468 dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size; 490 dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size
491 - cxt->pmsg_size;
469 err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz); 492 err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz);
470 if (err) 493 if (err)
471 goto fail_out; 494 goto fail_out;
@@ -480,6 +503,10 @@ static int ramoops_probe(struct platform_device *pdev)
480 if (err) 503 if (err)
481 goto fail_init_fprz; 504 goto fail_init_fprz;
482 505
506 err = ramoops_init_prz(dev, cxt, &cxt->mprz, &paddr, cxt->pmsg_size, 0);
507 if (err)
508 goto fail_init_mprz;
509
483 cxt->pstore.data = cxt; 510 cxt->pstore.data = cxt;
484 /* 511 /*
485 * Console can handle any buffer size, so prefer LOG_LINE_MAX. If we 512 * Console can handle any buffer size, so prefer LOG_LINE_MAX. If we
@@ -523,6 +550,8 @@ fail_buf:
523 kfree(cxt->pstore.buf); 550 kfree(cxt->pstore.buf);
524fail_clear: 551fail_clear:
525 cxt->pstore.bufsize = 0; 552 cxt->pstore.bufsize = 0;
553 kfree(cxt->mprz);
554fail_init_mprz:
526 kfree(cxt->fprz); 555 kfree(cxt->fprz);
527fail_init_fprz: 556fail_init_fprz:
528 kfree(cxt->cprz); 557 kfree(cxt->cprz);
@@ -580,6 +609,7 @@ static void ramoops_register_dummy(void)
580 dummy_data->record_size = record_size; 609 dummy_data->record_size = record_size;
581 dummy_data->console_size = ramoops_console_size; 610 dummy_data->console_size = ramoops_console_size;
582 dummy_data->ftrace_size = ramoops_ftrace_size; 611 dummy_data->ftrace_size = ramoops_ftrace_size;
612 dummy_data->pmsg_size = ramoops_pmsg_size;
583 dummy_data->dump_oops = dump_oops; 613 dummy_data->dump_oops = dump_oops;
584 /* 614 /*
585 * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC 615 * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index ece0c6bbfcc5..8884f6e507f7 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -39,6 +39,7 @@ enum pstore_type_id {
39 PSTORE_TYPE_PPC_RTAS = 4, 39 PSTORE_TYPE_PPC_RTAS = 4,
40 PSTORE_TYPE_PPC_OF = 5, 40 PSTORE_TYPE_PPC_OF = 5,
41 PSTORE_TYPE_PPC_COMMON = 6, 41 PSTORE_TYPE_PPC_COMMON = 6,
42 PSTORE_TYPE_PMSG = 7,
42 PSTORE_TYPE_UNKNOWN = 255 43 PSTORE_TYPE_UNKNOWN = 255
43}; 44};
44 45
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
index 4af3fdc85b01..9c9d6c154c8e 100644
--- a/include/linux/pstore_ram.h
+++ b/include/linux/pstore_ram.h
@@ -81,6 +81,7 @@ struct ramoops_platform_data {
81 unsigned long record_size; 81 unsigned long record_size;
82 unsigned long console_size; 82 unsigned long console_size;
83 unsigned long ftrace_size; 83 unsigned long ftrace_size;
84 unsigned long pmsg_size;
84 int dump_oops; 85 int dump_oops;
85 struct persistent_ram_ecc_info ecc_info; 86 struct persistent_ram_ecc_info ecc_info;
86}; 87};