linux/fs/pstore/pmsg.c
<<
>>
Prefs
   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}
 115