aboutsummaryrefslogtreecommitdiffstats
path: root/fs/pstore/pmsg.c
diff options
context:
space:
mode:
authorMark Salyzyn <salyzyn@android.com>2015-01-16 19:01:10 -0500
committerTony Luck <tony.luck@intel.com>2015-01-16 19:01:10 -0500
commit9d5438f462abd6398cdb7b3211bdcec271873a3b (patch)
treefeb8e50edd4180710602c0f4d2db9d76559da1f8 /fs/pstore/pmsg.c
parentf44f96528a8cd4134a4f2c1a9d8c785600aa4888 (diff)
pstore: Add pmsg - user-space accessible pstore object
A secured user-space accessible pstore object. Writes to /dev/pmsg0 are appended to the buffer, on reboot the persistent contents are available in /sys/fs/pstore/pmsg-ramoops-[ID]. One possible use is syslogd, or other daemon, can write messages, then on reboot provides a means to triage user-space activities leading up to a panic as a companion to the pstore dmesg or console logs. Signed-off-by: Mark Salyzyn <salyzyn@android.com> Acked-by: Kees Cook <keescook@chromium.org> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'fs/pstore/pmsg.c')
-rw-r--r--fs/pstore/pmsg.c114
1 files changed, 114 insertions, 0 deletions
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}