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}
 163static CLASS_ATTR_RW(disabled);
 164
 165static struct attribute *devcd_class_attrs[] = {
 166        &class_attr_disabled.attr,
 167        NULL,
 168};
 169ATTRIBUTE_GROUPS(devcd_class);
 170
 171static struct class devcd_class = {
 172        .name           = "devcoredump",
 173        .owner          = THIS_MODULE,
 174        .dev_release    = devcd_dev_release,
 175        .dev_groups     = devcd_dev_groups,
 176        .class_groups   = devcd_class_groups,
 177};
 178
 179static ssize_t devcd_readv(char *buffer, loff_t offset, size_t count,
 180                           void *data, size_t datalen)
 181{
 182        if (offset > datalen)
 183                return -EINVAL;
 184
 185        if (offset + count > datalen)
 186                count = datalen - offset;
 187
 188        if (count)
 189                memcpy(buffer, ((u8 *)data) + offset, count);
 190
 191        return count;
 192}
 193
 194static void devcd_freev(void *data)
 195{
 196        vfree(data);
 197}
 198
 199/**
 200 * dev_coredumpv - create device coredump with vmalloc data
 201 * @dev: the struct device for the crashed device
 202 * @data: vmalloc data containing the device coredump
 203 * @datalen: length of the data
 204 * @gfp: allocation flags
 205 *
 206 * This function takes ownership of the vmalloc'ed data and will free
 207 * it when it is no longer used. See dev_coredumpm() for more information.
 208 */
 209void dev_coredumpv(struct device *dev, void *data, size_t datalen,
 210                   gfp_t gfp)
 211{
 212        dev_coredumpm(dev, NULL, data, datalen, gfp, devcd_readv, devcd_freev);
 213}
 214EXPORT_SYMBOL_GPL(dev_coredumpv);
 215
 216static int devcd_match_failing(struct device *dev, const void *failing)
 217{
 218        struct devcd_entry *devcd = dev_to_devcd(dev);
 219
 220        return devcd->failing_dev == failing;
 221}
 222
 223/**
 224 * devcd_free_sgtable - free all the memory of the given scatterlist table
 225 * (i.e. both pages and scatterlist instances)
 226 * NOTE: if two tables allocated with devcd_alloc_sgtable and then chained
 227 * using the sg_chain function then that function should be called only once
 228 * on the chained table
 229 * @table: pointer to sg_table to free
 230 */
 231static void devcd_free_sgtable(void *data)
 232{
 233        _devcd_free_sgtable(data);
 234}
 235
 236/**
 237 * devcd_read_from_table - copy data from sg_table to a given buffer
 238 * and return the number of bytes read
 239 * @buffer: the buffer to copy the data to it
 240 * @buf_len: the length of the buffer
 241 * @data: the scatterlist table to copy from
 242 * @offset: start copy from @offset@ bytes from the head of the data
 243 *      in the given scatterlist
 244 * @data_len: the length of the data in the sg_table
 245 */
 246static ssize_t devcd_read_from_sgtable(char *buffer, loff_t offset,
 247                                       size_t buf_len, void *data,
 248                                       size_t data_len)
 249{
 250        struct scatterlist *table = data;
 251
 252        if (offset > data_len)
 253                return -EINVAL;
 254
 255        if (offset + buf_len > data_len)
 256                buf_len = data_len - offset;
 257        return sg_pcopy_to_buffer(table, sg_nents(table), buffer, buf_len,
 258                                  offset);
 259}
 260
 261/**
 262 * dev_coredumpm - create device coredump with read/free methods
 263 * @dev: the struct device for the crashed device
 264 * @owner: the module that contains the read/free functions, use %THIS_MODULE
 265 * @data: data cookie for the @read/@free functions
 266 * @datalen: length of the data
 267 * @gfp: allocation flags
 268 * @read: function to read from the given buffer
 269 * @free: function to free the given buffer
 270 *
 271 * Creates a new device coredump for the given device. If a previous one hasn't
 272 * been read yet, the new coredump is discarded. The data lifetime is determined
 273 * by the device coredump framework and when it is no longer needed the @free
 274 * function will be called to free the data.
 275 */
 276void dev_coredumpm(struct device *dev, struct module *owner,
 277                   void *data, size_t datalen, gfp_t gfp,
 278                   ssize_t (*read)(char *buffer, loff_t offset, size_t count,
 279                                   void *data, size_t datalen),
 280                   void (*free)(void *data))
 281{
 282        static atomic_t devcd_count = ATOMIC_INIT(0);
 283        struct devcd_entry *devcd;
 284        struct device *existing;
 285
 286        if (devcd_disabled)
 287                goto free;
 288
 289        existing = class_find_device(&devcd_class, NULL, dev,
 290                                     devcd_match_failing);
 291        if (existing) {
 292                put_device(existing);
 293                goto free;
 294        }
 295
 296        if (!try_module_get(owner))
 297                goto free;
 298
 299        devcd = kzalloc(sizeof(*devcd), gfp);
 300        if (!devcd)
 301                goto put_module;
 302
 303        devcd->owner = owner;
 304        devcd->data = data;
 305        devcd->datalen = datalen;
 306        devcd->read = read;
 307        devcd->free = free;
 308        devcd->failing_dev = get_device(dev);
 309
 310        device_initialize(&devcd->devcd_dev);
 311
 312        dev_set_name(&devcd->devcd_dev, "devcd%d",
 313                     atomic_inc_return(&devcd_count));
 314        devcd->devcd_dev.class = &devcd_class;
 315
 316        if (device_add(&devcd->devcd_dev))
 317                goto put_device;
 318
 319        if (sysfs_create_link(&devcd->devcd_dev.kobj, &dev->kobj,
 320                              "failing_device"))
 321                /* nothing - symlink will be missing */;
 322
 323        if (sysfs_create_link(&dev->kobj, &devcd->devcd_dev.kobj,
 324                              "devcoredump"))
 325                /* nothing - symlink will be missing */;
 326
 327        INIT_DELAYED_WORK(&devcd->del_wk, devcd_del);
 328        schedule_delayed_work(&devcd->del_wk, DEVCD_TIMEOUT);
 329
 330        return;
 331 put_device:
 332        put_device(&devcd->devcd_dev);
 333 put_module:
 334        module_put(owner);
 335 free:
 336        free(data);
 337}
 338EXPORT_SYMBOL_GPL(dev_coredumpm);
 339
 340/**
 341 * dev_coredumpmsg - create device coredump that uses scatterlist as data
 342 * parameter
 343 * @dev: the struct device for the crashed device
 344 * @table: the dump data
 345 * @datalen: length of the data
 346 * @gfp: allocation flags
 347 *
 348 * Creates a new device coredump for the given device. If a previous one hasn't
 349 * been read yet, the new coredump is discarded. The data lifetime is determined
 350 * by the device coredump framework and when it is no longer needed
 351 * it will free the data.
 352 */
 353void dev_coredumpsg(struct device *dev, struct scatterlist *table,
 354                    size_t datalen, gfp_t gfp)
 355{
 356        dev_coredumpm(dev, NULL, table, datalen, gfp, devcd_read_from_sgtable,
 357                      devcd_free_sgtable);
 358}
 359EXPORT_SYMBOL_GPL(dev_coredumpsg);
 360
 361static int __init devcoredump_init(void)
 362{
 363        return class_register(&devcd_class);
 364}
 365__initcall(devcoredump_init);
 366
 367static void __exit devcoredump_exit(void)
 368{
 369        class_for_each_device(&devcd_class, NULL, NULL, devcd_free);
 370        class_unregister(&devcd_class);
 371}
 372__exitcall(devcoredump_exit);
 373