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