pmsg.c (1965B)
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 12static DEFINE_MUTEX(pmsg_lock); 13 14static 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 37static const struct file_operations pmsg_fops = { 38 .owner = THIS_MODULE, 39 .llseek = noop_llseek, 40 .write = write_pmsg, 41}; 42 43static struct class *pmsg_class; 44static int pmsg_major; 45#define PMSG_NAME "pmsg" 46#undef pr_fmt 47#define pr_fmt(fmt) PMSG_NAME ": " fmt 48 49static char *pmsg_devnode(struct device *dev, umode_t *mode) 50{ 51 if (mode) 52 *mode = 0220; 53 return NULL; 54} 55 56void 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 81err_device: 82 class_destroy(pmsg_class); 83err_class: 84 unregister_chrdev(pmsg_major, PMSG_NAME); 85err: 86 return; 87} 88 89void 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}