linux/drivers/base/devcoredump.c
<<
>>
Prefs
   1/*
   2 * This file is provided under the GPLv2 license.
   3 *
   4 * GPL LICENSE SUMMARY
   5 *
   6 * Copyright(c) 2014 Intel Mobile Communications GmbH
   7 * Copyright(c) 2015 Intel Deutschland GmbH
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of version 2 of the GNU General Public License as
  11 * published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope that it will be useful, but
  14 * WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16 * General Public License for more details.
  17 *
  18 * The full GNU General Public License is included in this distribution
  19 * in the file called COPYING.
  20 *
  21 * Contact Information:
  22 *  Intel Linux Wireless <ilw@linux.intel.com>
  23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  24 *
  25 * Author: Johannes Berg <johannes@sipsolutions.net>
  26 */
  27#include <linux/module.h>
  28#include <linux/device.h>
  29#include <linux/devcoredump.h>
  30#include <linux/list.h>
  31#include <linux/slab.h>
  32#include <linux/fs.h>
  33#include <linux/workqueue.h>
  34
  35static struct class devcd_class;
  36
  37/* global disable flag, for security purposes */
  38static bool devcd_disabled;
  39
  40/* if data isn't read by userspace after 5 minutes then delete it */
  41#define DEVCD_TIMEOUT   (HZ * 60 * 5)
  42
  43struct devcd_entry {
  44        struct device devcd_dev;
  45        void *data;
  46        size_t datalen;
  47        struct module *owner;
  48        ssize_t (*read)(char *buffer, loff_t offset, size_t count,
  49                        void *data, size_t datalen);
  50        void (*free)(void *data);
  51        struct delayed_work del_wk;
  52        struct device *failing_dev;
  53};
  54
  55static struct devcd_entry *dev_to_devcd(struct device *dev)
  56{
  57        return container_of(dev, struct devcd_entry, devcd_dev);
  58}
  59
  60static void devcd_dev_release(struct device *dev)
  61{
  62        struct devcd_entry *devcd = dev_to_devcd(dev);
  63
  64        devcd->free(devcd->data);
  65        module_put(devcd->owner);
  66
  67        /*
  68         * this seems racy, but I don't see a notifier or such on
  69         * a struct device to know when it goes away?
  70         */
  71        if (devcd->failing_dev->kobj.sd)
  72                sysfs_delete_link(&devcd->failing_dev->kobj, &dev->kobj,
  73                                  "devcoredump");
  74
  75        put_device(devcd->failing_dev);
  76        kfree(devcd);
  77}
  78
  79static void devcd_del(struct work_struct *wk)
  80{
  81        struct devcd_entry *devcd;
  82
  83        devcd = container_of(wk, struct devcd_entry, del_wk.work);
  84
  85        device_del(&devcd->devcd_dev);
  86        put_device(&devcd->devcd_dev);
  87}
  88
  89static ssize_t devcd_data_read(struct file *filp, struct kobject *kobj,
  90                               struct bin_attribute *bin_attr,
  91                               char *buffer, loff_t offset, size_t count)
  92{
  93        struct device *dev = kobj_to_dev(kobj);
  94        struct devcd_entry *devcd = dev_to_devcd(dev);
  95
  96        return devcd->read(buffer, offset, count, devcd->data, devcd->datalen);
  97}
  98
  99static ssize_t devcd_data_write(struct file *filp, struct kobject *kobj,
 100                                struct bin_attribute *bin_attr,
 101                                char *buffer, loff_t offset, size_t count)
 102{
 103        struct device *dev = kobj_to_dev(kobj);
 104        struct devcd_entry *devcd = dev_to_devcd(dev);
 105
 106        mod_delayed_work(system_wq, &devcd->del_wk, 0);
 107
 108        return count;
 109}
 110
 111static struct bin_attribute devcd_attr_data = {
 112        .attr = { .name = "data", .mode = S_IRUSR | S_IWUSR, },
 113        .size = 0,
 114        .read = devcd_data_read,
 115        .write = devcd_data_write,
 116};
 117
 118static struct bin_attribute *devcd_dev_bin_attrs[] = {
 119        &devcd_attr_data, NULL,
 120};
 121
 122static const struct attribute_group devcd_dev_group = {
 123        .bin_attrs = devcd_dev_bin_attrs,
 124};
 125
 126static const struct attribute_group *devcd_dev_groups[] = {
 127        &devcd_dev_group, NULL,
 128};
 129
 130static int devcd_free(struct device *dev, void *data)
 131{
 132        struct devcd_entry *devcd = dev_to_devcd(dev);
 133
 134        flush_delayed_work(&devcd->del_wk);
 135        return 0;
 136}
 137
 138static ssize_t disabled_show(struct class *class, struct class_attribute *attr,
 139                             char *buf)
 140{
 141        return sprintf(buf, "%d\n", devcd_disabled);
 142}
 143
 144static ssize_t disabled_store(struct class *class, struct class_attribute *attr,
 145                              const char *buf, size_t count)
 146{
 147        long tmp = simple_strtol(buf, NULL, 10);
 148
 149        /*
 150         * This essentially makes the attribute write-once, since you can't
 151         * go back to not having it disabled. This is intentional, it serves
 152         * as a system lockdown feature.
 153         */
 154        if (tmp != 1)
 155                return -EINVAL;
 156
 157        devcd_disabled = true;
 158
 159        class_for_each_device(&devcd_class, NULL, NULL, devcd_free);
 160
 161        return count;
 162}
 163
 164static struct class_attribute devcd_class_attrs[] = {
 165        __ATTR_RW(disabled),
 166        __ATTR_NULL
 167};
 168
 169static struct class devcd_class = {
 170        .name           = "devcoredump",
 171        .owner          = THIS_MODULE,
 172        .dev_release    = devcd_dev_release,
 173        .dev_groups     = devcd_dev_groups,
 174        .class_attrs    = devcd_class_attrs,
 175};
 176
 177static ssize_t devcd_readv(char *buffer, loff_t offset, size_t count,
 178                           void *data, size_t datalen)
 179{
 180        if (offset > datalen)
 181                return -EINVAL;
 182
 183        if (offset + count > datalen)
 184                count = datalen - offset;
 185
 186        if (count)
 187                memcpy(buffer, ((u8 *)data) + offset, count);
 188
 189        return count;
 190}
 191
 192static void devcd_freev(void *data)
 193{
 194        vfree(data);
 195}
 196
 197/**
 198 * dev_coredumpv - create device coredump with vmalloc data
 199 * @dev: the struct device for the crashed device
 200 * @data: vmalloc data containing the device coredump
 201 * @datalen: length of the data
 202 * @gfp: allocation flags
 203 *
 204 * This function takes ownership of the vmalloc'ed data and will free
 205 * it when it is no longer used. See dev_coredumpm() for more information.
 206 */
 207void dev_coredumpv(struct device *dev, void *data, size_t datalen,
 208                   gfp_t gfp)
 209{
 210        dev_coredumpm(dev, NULL, data, datalen, gfp, devcd_readv, devcd_freev);
 211}
 212EXPORT_SYMBOL_GPL(dev_coredumpv);
 213
 214static int devcd_match_failing(struct device *dev, const void *failing)
 215{
 216        struct devcd_entry *devcd = dev_to_devcd(dev);
 217
 218        return devcd->failing_dev == failing;
 219}
 220
 221/**
 222 * devcd_free_sgtable - free all the memory of the given scatterlist table
 223 * (i.e. both pages and scatterlist instances)
 224 * NOTE: if two tables allocated with devcd_alloc_sgtable and then chained
 225 * using the sg_chain function then that function should be called only once
 226 * on the chained table
 227 * @table: pointer to sg_table to free
 228 */
 229static void devcd_free_sgtable(void *data)
 230{
 231        _devcd_free_sgtable(data);
 232}
 233
 234/**
 235 * devcd_read_from_table - copy data from sg_table to a given buffer
 236 * and return the number of bytes read
 237 * @buffer: the buffer to copy the data to it
 238 * @buf_len: the length of the buffer
 239 * @data: the scatterlist table to copy from
 240 * @offset: start copy from @offset@ bytes from the head of the data
 241 *      in the given scatterlist
 242 * @data_len: the length of the data in the sg_table
 243 */
 244static ssize_t devcd_read_from_sgtable(char *buffer, loff_t offset,
 245                                       size_t buf_len, void *data,
 246                                       size_t data_len)
 247{
 248        struct scatterlist *table = data;
 249
 250        if (offset > data_len)
 251                return -EINVAL;
 252
 253        if (offset + buf_len > data_len)
 254                buf_len = data_len - offset;
 255        return sg_pcopy_to_buffer(table, sg_nents(table), buffer, buf_len,
 256                                  offset);
 257}
 258
 259/**
 260 * dev_coredumpm - create device coredump with read/free methods
 261 * @dev: the struct device for the crashed device
 262 * @owner: the module that contains the read/free functions, use %THIS_MODULE
 263 * @data: data cookie for the @read/@free functions
 264 * @datalen: length of the data
 265 * @gfp: allocation flags
 266 * @read: function to read from the given buffer
 267 * @free: function to free the given buffer
 268 *
 269 * Creates a new device coredump for the given device. If a previous one hasn't
 270 * been read yet, the new coredump is discarded. The data lifetime is determined
 271 * by the device coredump framework and when it is no longer needed the @free
 272 * function will be called to free the data.
 273 */
 274void dev_coredumpm(struct device *dev, struct module *owner,
 275                   void *data, size_t datalen, gfp_t gfp,
 276                   ssize_t (*read)(char *buffer, loff_t offset, size_t count,
 277                                   void *data, size_t datalen),
 278                   void (*free)(void *data))
 279{
 280        static atomic_t devcd_count = ATOMIC_INIT(0);
 281        struct devcd_entry *devcd;
 282        struct device *existing;
 283
 284        if (devcd_disabled)
 285                goto free;
 286
 287        existing = class_find_device(&devcd_class, NULL, dev,
 288                                     devcd_match_failing);
 289        if (existing) {
 290                put_device(existing);
 291                goto free;
 292        }
 293
 294        if (!try_module_get(owner))
 295                goto free;
 296
 297        devcd = kzalloc(sizeof(*devcd), gfp);
 298        if (!devcd)
 299                goto put_module;
 300
 301        devcd->owner = owner;
 302        devcd->data = data;
 303        devcd->datalen = datalen;
 304        devcd->read = read;
 305        devcd->free = free;
 306        devcd->failing_dev = get_device(dev);
 307
 308        device_initialize(&devcd->devcd_dev);
 309
 310        dev_set_name(&devcd->devcd_dev, "devcd%d",
 311                     atomic_inc_return(&devcd_count));
 312        devcd->devcd_dev.class = &devcd_class;
 313
 314        if (device_add(&devcd->devcd_dev))
 315                goto put_device;
 316
 317        if (sysfs_create_link(&devcd->devcd_dev.kobj, &dev->kobj,
 318                              "failing_device"))
 319                /* nothing - symlink will be missing */;
 320
 321        if (sysfs_create_link(&dev->kobj, &devcd->devcd_dev.kobj,
 322                              "devcoredump"))
 323                /* nothing - symlink will be missing */;
 324
 325        INIT_DELAYED_WORK(&devcd->del_wk, devcd_del);
 326        schedule_delayed_work(&devcd->del_wk, DEVCD_TIMEOUT);
 327
 328        return;
 329 put_device:
 330        put_device(&devcd->devcd_dev);
 331 put_module:
 332        module_put(owner);
 333 free:
 334        free(data);
 335}
 336EXPORT_SYMBOL_GPL(dev_coredumpm);
 337
 338/**
 339 * dev_coredumpmsg - create device coredump that uses scatterlist as data
 340 * parameter
 341 * @dev: the struct device for the crashed device
 342 * @table: the dump data
 343 * @datalen: length of the data
 344 * @gfp: allocation flags
 345 *
 346 * Creates a new device coredump for the given device. If a previous one hasn't
 347 * been read yet, the new coredump is discarded. The data lifetime is determined
 348 * by the device coredump framework and when it is no longer needed
 349 * it will free the data.
 350 */
 351void dev_coredumpsg(struct device *dev, struct scatterlist *table,
 352                    size_t datalen, gfp_t gfp)
 353{
 354        dev_coredumpm(dev, NULL, table, datalen, gfp, devcd_read_from_sgtable,
 355                      devcd_free_sgtable);
 356}
 357EXPORT_SYMBOL_GPL(dev_coredumpsg);
 358
 359static int __init devcoredump_init(void)
 360{
 361        return class_register(&devcd_class);
 362}
 363__initcall(devcoredump_init);
 364
 365static void __exit devcoredump_exit(void)
 366{
 367        class_for_each_device(&devcd_class, NULL, NULL, devcd_free);
 368        class_unregister(&devcd_class);
 369}
 370__exitcall(devcoredump_exit);
 371