mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 06:34:12 +08:00
9c92ab6191
Based on 1 normalized pattern(s): this software is licensed under the terms of the gnu general public license version 2 as published by the free software foundation and may be copied distributed and modified under those terms this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference in 285 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Alexios Zavras <alexios.zavras@intel.com> Reviewed-by: Allison Randal <allison@lohutok.net> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190529141900.642774971@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
95 lines
1.9 KiB
C
95 lines
1.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright 2014 Google, Inc.
|
|
*/
|
|
|
|
#include <linux/cdev.h>
|
|
#include <linux/device.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/uaccess.h>
|
|
#include "internal.h"
|
|
|
|
static DEFINE_MUTEX(pmsg_lock);
|
|
|
|
static ssize_t write_pmsg(struct file *file, const char __user *buf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
struct pstore_record record;
|
|
int ret;
|
|
|
|
if (!count)
|
|
return 0;
|
|
|
|
pstore_record_init(&record, psinfo);
|
|
record.type = PSTORE_TYPE_PMSG;
|
|
record.size = count;
|
|
|
|
/* check outside lock, page in any data. write_user also checks */
|
|
if (!access_ok(buf, count))
|
|
return -EFAULT;
|
|
|
|
mutex_lock(&pmsg_lock);
|
|
ret = psinfo->write_user(&record, buf);
|
|
mutex_unlock(&pmsg_lock);
|
|
return ret ? ret : count;
|
|
}
|
|
|
|
static const struct file_operations pmsg_fops = {
|
|
.owner = THIS_MODULE,
|
|
.llseek = noop_llseek,
|
|
.write = write_pmsg,
|
|
};
|
|
|
|
static struct class *pmsg_class;
|
|
static int pmsg_major;
|
|
#define PMSG_NAME "pmsg"
|
|
#undef pr_fmt
|
|
#define pr_fmt(fmt) PMSG_NAME ": " fmt
|
|
|
|
static char *pmsg_devnode(struct device *dev, umode_t *mode)
|
|
{
|
|
if (mode)
|
|
*mode = 0220;
|
|
return NULL;
|
|
}
|
|
|
|
void pstore_register_pmsg(void)
|
|
{
|
|
struct device *pmsg_device;
|
|
|
|
pmsg_major = register_chrdev(0, PMSG_NAME, &pmsg_fops);
|
|
if (pmsg_major < 0) {
|
|
pr_err("register_chrdev failed\n");
|
|
goto err;
|
|
}
|
|
|
|
pmsg_class = class_create(THIS_MODULE, PMSG_NAME);
|
|
if (IS_ERR(pmsg_class)) {
|
|
pr_err("device class file already in use\n");
|
|
goto err_class;
|
|
}
|
|
pmsg_class->devnode = pmsg_devnode;
|
|
|
|
pmsg_device = device_create(pmsg_class, NULL, MKDEV(pmsg_major, 0),
|
|
NULL, "%s%d", PMSG_NAME, 0);
|
|
if (IS_ERR(pmsg_device)) {
|
|
pr_err("failed to create device\n");
|
|
goto err_device;
|
|
}
|
|
return;
|
|
|
|
err_device:
|
|
class_destroy(pmsg_class);
|
|
err_class:
|
|
unregister_chrdev(pmsg_major, PMSG_NAME);
|
|
err:
|
|
return;
|
|
}
|
|
|
|
void pstore_unregister_pmsg(void)
|
|
{
|
|
device_destroy(pmsg_class, MKDEV(pmsg_major, 0));
|
|
class_destroy(pmsg_class);
|
|
unregister_chrdev(pmsg_major, PMSG_NAME);
|
|
}
|