xref: /openbmc/linux/fs/pstore/pmsg.c (revision 8795a739)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright 2014  Google, Inc.
4  */
5 
6 #include <linux/cdev.h>
7 #include <linux/device.h>
8 #include <linux/fs.h>
9 #include <linux/uaccess.h>
10 #include "internal.h"
11 
12 static DEFINE_MUTEX(pmsg_lock);
13 
14 static ssize_t write_pmsg(struct file *file, const char __user *buf,
15 			  size_t count, loff_t *ppos)
16 {
17 	struct pstore_record record;
18 	int ret;
19 
20 	if (!count)
21 		return 0;
22 
23 	pstore_record_init(&record, psinfo);
24 	record.type = PSTORE_TYPE_PMSG;
25 	record.size = count;
26 
27 	/* check outside lock, page in any data. write_user also checks */
28 	if (!access_ok(buf, count))
29 		return -EFAULT;
30 
31 	mutex_lock(&pmsg_lock);
32 	ret = psinfo->write_user(&record, buf);
33 	mutex_unlock(&pmsg_lock);
34 	return ret ? ret : count;
35 }
36 
37 static const struct file_operations pmsg_fops = {
38 	.owner		= THIS_MODULE,
39 	.llseek		= noop_llseek,
40 	.write		= write_pmsg,
41 };
42 
43 static struct class *pmsg_class;
44 static int pmsg_major;
45 #define PMSG_NAME "pmsg"
46 #undef pr_fmt
47 #define pr_fmt(fmt) PMSG_NAME ": " fmt
48 
49 static char *pmsg_devnode(struct device *dev, umode_t *mode)
50 {
51 	if (mode)
52 		*mode = 0220;
53 	return NULL;
54 }
55 
56 void pstore_register_pmsg(void)
57 {
58 	struct device *pmsg_device;
59 
60 	pmsg_major = register_chrdev(0, PMSG_NAME, &pmsg_fops);
61 	if (pmsg_major < 0) {
62 		pr_err("register_chrdev failed\n");
63 		goto err;
64 	}
65 
66 	pmsg_class = class_create(THIS_MODULE, PMSG_NAME);
67 	if (IS_ERR(pmsg_class)) {
68 		pr_err("device class file already in use\n");
69 		goto err_class;
70 	}
71 	pmsg_class->devnode = pmsg_devnode;
72 
73 	pmsg_device = device_create(pmsg_class, NULL, MKDEV(pmsg_major, 0),
74 					NULL, "%s%d", PMSG_NAME, 0);
75 	if (IS_ERR(pmsg_device)) {
76 		pr_err("failed to create device\n");
77 		goto err_device;
78 	}
79 	return;
80 
81 err_device:
82 	class_destroy(pmsg_class);
83 err_class:
84 	unregister_chrdev(pmsg_major, PMSG_NAME);
85 err:
86 	return;
87 }
88 
89 void pstore_unregister_pmsg(void)
90 {
91 	device_destroy(pmsg_class, MKDEV(pmsg_major, 0));
92 	class_destroy(pmsg_class);
93 	unregister_chrdev(pmsg_major, PMSG_NAME);
94 }
95