1833c95456a70826d1384883b73fd23aff24d366fJohannes Berg/* 2833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * This file is provided under the GPLv2 license. 3833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * 4833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * GPL LICENSE SUMMARY 5833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * 6833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * Copyright(c) 2014 Intel Mobile Communications GmbH 7833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * 8833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * This program is free software; you can redistribute it and/or modify 9833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * it under the terms of version 2 of the GNU General Public License as 10833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * published by the Free Software Foundation. 11833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * 12833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * This program is distributed in the hope that it will be useful, but 13833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * WITHOUT ANY WARRANTY; without even the implied warranty of 14833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * General Public License for more details. 16833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * 17833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * The full GNU General Public License is included in this distribution 18833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * in the file called COPYING. 19833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * 20833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * Contact Information: 21833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * Intel Linux Wireless <ilw@linux.intel.com> 22833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 23833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * 24833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * Author: Johannes Berg <johannes@sipsolutions.net> 25833c95456a70826d1384883b73fd23aff24d366fJohannes Berg */ 26833c95456a70826d1384883b73fd23aff24d366fJohannes Berg#include <linux/module.h> 27833c95456a70826d1384883b73fd23aff24d366fJohannes Berg#include <linux/device.h> 28833c95456a70826d1384883b73fd23aff24d366fJohannes Berg#include <linux/devcoredump.h> 29833c95456a70826d1384883b73fd23aff24d366fJohannes Berg#include <linux/list.h> 30833c95456a70826d1384883b73fd23aff24d366fJohannes Berg#include <linux/slab.h> 31833c95456a70826d1384883b73fd23aff24d366fJohannes Berg#include <linux/fs.h> 32833c95456a70826d1384883b73fd23aff24d366fJohannes Berg#include <linux/workqueue.h> 33833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 34833c95456a70826d1384883b73fd23aff24d366fJohannes Berg/* if data isn't read by userspace after 5 minutes then delete it */ 35833c95456a70826d1384883b73fd23aff24d366fJohannes Berg#define DEVCD_TIMEOUT (HZ * 60 * 5) 36833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 37833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstruct devcd_entry { 38833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct device devcd_dev; 39833c95456a70826d1384883b73fd23aff24d366fJohannes Berg const void *data; 40833c95456a70826d1384883b73fd23aff24d366fJohannes Berg size_t datalen; 41833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct module *owner; 42833c95456a70826d1384883b73fd23aff24d366fJohannes Berg ssize_t (*read)(char *buffer, loff_t offset, size_t count, 43833c95456a70826d1384883b73fd23aff24d366fJohannes Berg const void *data, size_t datalen); 44833c95456a70826d1384883b73fd23aff24d366fJohannes Berg void (*free)(const void *data); 45833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct delayed_work del_wk; 46833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct device *failing_dev; 47833c95456a70826d1384883b73fd23aff24d366fJohannes Berg}; 48833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 49833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic struct devcd_entry *dev_to_devcd(struct device *dev) 50833c95456a70826d1384883b73fd23aff24d366fJohannes Berg{ 51833c95456a70826d1384883b73fd23aff24d366fJohannes Berg return container_of(dev, struct devcd_entry, devcd_dev); 52833c95456a70826d1384883b73fd23aff24d366fJohannes Berg} 53833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 54833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic void devcd_dev_release(struct device *dev) 55833c95456a70826d1384883b73fd23aff24d366fJohannes Berg{ 56833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct devcd_entry *devcd = dev_to_devcd(dev); 57833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 58833c95456a70826d1384883b73fd23aff24d366fJohannes Berg devcd->free(devcd->data); 59833c95456a70826d1384883b73fd23aff24d366fJohannes Berg module_put(devcd->owner); 60833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 61833c95456a70826d1384883b73fd23aff24d366fJohannes Berg /* 62833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * this seems racy, but I don't see a notifier or such on 63833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * a struct device to know when it goes away? 64833c95456a70826d1384883b73fd23aff24d366fJohannes Berg */ 65833c95456a70826d1384883b73fd23aff24d366fJohannes Berg if (devcd->failing_dev->kobj.sd) 66833c95456a70826d1384883b73fd23aff24d366fJohannes Berg sysfs_delete_link(&devcd->failing_dev->kobj, &dev->kobj, 67833c95456a70826d1384883b73fd23aff24d366fJohannes Berg "devcoredump"); 68833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 69833c95456a70826d1384883b73fd23aff24d366fJohannes Berg put_device(devcd->failing_dev); 70833c95456a70826d1384883b73fd23aff24d366fJohannes Berg kfree(devcd); 71833c95456a70826d1384883b73fd23aff24d366fJohannes Berg} 72833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 73833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic void devcd_del(struct work_struct *wk) 74833c95456a70826d1384883b73fd23aff24d366fJohannes Berg{ 75833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct devcd_entry *devcd; 76833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 77833c95456a70826d1384883b73fd23aff24d366fJohannes Berg devcd = container_of(wk, struct devcd_entry, del_wk.work); 78833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 79833c95456a70826d1384883b73fd23aff24d366fJohannes Berg device_del(&devcd->devcd_dev); 80833c95456a70826d1384883b73fd23aff24d366fJohannes Berg put_device(&devcd->devcd_dev); 81833c95456a70826d1384883b73fd23aff24d366fJohannes Berg} 82833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 83833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic ssize_t devcd_data_read(struct file *filp, struct kobject *kobj, 84833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct bin_attribute *bin_attr, 85833c95456a70826d1384883b73fd23aff24d366fJohannes Berg char *buffer, loff_t offset, size_t count) 86833c95456a70826d1384883b73fd23aff24d366fJohannes Berg{ 87833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct device *dev = kobj_to_dev(kobj); 88833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct devcd_entry *devcd = dev_to_devcd(dev); 89833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 90833c95456a70826d1384883b73fd23aff24d366fJohannes Berg return devcd->read(buffer, offset, count, devcd->data, devcd->datalen); 91833c95456a70826d1384883b73fd23aff24d366fJohannes Berg} 92833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 93833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic ssize_t devcd_data_write(struct file *filp, struct kobject *kobj, 94833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct bin_attribute *bin_attr, 95833c95456a70826d1384883b73fd23aff24d366fJohannes Berg char *buffer, loff_t offset, size_t count) 96833c95456a70826d1384883b73fd23aff24d366fJohannes Berg{ 97833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct device *dev = kobj_to_dev(kobj); 98833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct devcd_entry *devcd = dev_to_devcd(dev); 99833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 100833c95456a70826d1384883b73fd23aff24d366fJohannes Berg mod_delayed_work(system_wq, &devcd->del_wk, 0); 101833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 102833c95456a70826d1384883b73fd23aff24d366fJohannes Berg return count; 103833c95456a70826d1384883b73fd23aff24d366fJohannes Berg} 104833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 105833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic struct bin_attribute devcd_attr_data = { 106833c95456a70826d1384883b73fd23aff24d366fJohannes Berg .attr = { .name = "data", .mode = S_IRUSR | S_IWUSR, }, 107833c95456a70826d1384883b73fd23aff24d366fJohannes Berg .size = 0, 108833c95456a70826d1384883b73fd23aff24d366fJohannes Berg .read = devcd_data_read, 109833c95456a70826d1384883b73fd23aff24d366fJohannes Berg .write = devcd_data_write, 110833c95456a70826d1384883b73fd23aff24d366fJohannes Berg}; 111833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 112833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic struct bin_attribute *devcd_dev_bin_attrs[] = { 113833c95456a70826d1384883b73fd23aff24d366fJohannes Berg &devcd_attr_data, NULL, 114833c95456a70826d1384883b73fd23aff24d366fJohannes Berg}; 115833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 116833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic const struct attribute_group devcd_dev_group = { 117833c95456a70826d1384883b73fd23aff24d366fJohannes Berg .bin_attrs = devcd_dev_bin_attrs, 118833c95456a70826d1384883b73fd23aff24d366fJohannes Berg}; 119833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 120833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic const struct attribute_group *devcd_dev_groups[] = { 121833c95456a70826d1384883b73fd23aff24d366fJohannes Berg &devcd_dev_group, NULL, 122833c95456a70826d1384883b73fd23aff24d366fJohannes Berg}; 123833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 124833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic struct class devcd_class = { 125833c95456a70826d1384883b73fd23aff24d366fJohannes Berg .name = "devcoredump", 126833c95456a70826d1384883b73fd23aff24d366fJohannes Berg .owner = THIS_MODULE, 127833c95456a70826d1384883b73fd23aff24d366fJohannes Berg .dev_release = devcd_dev_release, 128833c95456a70826d1384883b73fd23aff24d366fJohannes Berg .dev_groups = devcd_dev_groups, 129833c95456a70826d1384883b73fd23aff24d366fJohannes Berg}; 130833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 131833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic ssize_t devcd_readv(char *buffer, loff_t offset, size_t count, 132833c95456a70826d1384883b73fd23aff24d366fJohannes Berg const void *data, size_t datalen) 133833c95456a70826d1384883b73fd23aff24d366fJohannes Berg{ 134833c95456a70826d1384883b73fd23aff24d366fJohannes Berg if (offset > datalen) 135833c95456a70826d1384883b73fd23aff24d366fJohannes Berg return -EINVAL; 136833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 137833c95456a70826d1384883b73fd23aff24d366fJohannes Berg if (offset + count > datalen) 138833c95456a70826d1384883b73fd23aff24d366fJohannes Berg count = datalen - offset; 139833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 140833c95456a70826d1384883b73fd23aff24d366fJohannes Berg if (count) 141833c95456a70826d1384883b73fd23aff24d366fJohannes Berg memcpy(buffer, ((u8 *)data) + offset, count); 142833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 143833c95456a70826d1384883b73fd23aff24d366fJohannes Berg return count; 144833c95456a70826d1384883b73fd23aff24d366fJohannes Berg} 145833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 146833c95456a70826d1384883b73fd23aff24d366fJohannes Berg/** 147833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * dev_coredumpv - create device coredump with vmalloc data 148833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * @dev: the struct device for the crashed device 149833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * @data: vmalloc data containing the device coredump 150833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * @datalen: length of the data 151833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * @gfp: allocation flags 152833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * 153833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * This function takes ownership of the vmalloc'ed data and will free 154833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * it when it is no longer used. See dev_coredumpm() for more information. 155833c95456a70826d1384883b73fd23aff24d366fJohannes Berg */ 156833c95456a70826d1384883b73fd23aff24d366fJohannes Bergvoid dev_coredumpv(struct device *dev, const void *data, size_t datalen, 157833c95456a70826d1384883b73fd23aff24d366fJohannes Berg gfp_t gfp) 158833c95456a70826d1384883b73fd23aff24d366fJohannes Berg{ 159833c95456a70826d1384883b73fd23aff24d366fJohannes Berg dev_coredumpm(dev, NULL, data, datalen, gfp, devcd_readv, vfree); 160833c95456a70826d1384883b73fd23aff24d366fJohannes Berg} 161833c95456a70826d1384883b73fd23aff24d366fJohannes BergEXPORT_SYMBOL_GPL(dev_coredumpv); 162833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 163833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic int devcd_match_failing(struct device *dev, const void *failing) 164833c95456a70826d1384883b73fd23aff24d366fJohannes Berg{ 165833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct devcd_entry *devcd = dev_to_devcd(dev); 166833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 167833c95456a70826d1384883b73fd23aff24d366fJohannes Berg return devcd->failing_dev == failing; 168833c95456a70826d1384883b73fd23aff24d366fJohannes Berg} 169833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 170833c95456a70826d1384883b73fd23aff24d366fJohannes Berg/** 171833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * dev_coredumpm - create device coredump with read/free methods 172833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * @dev: the struct device for the crashed device 173833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * @owner: the module that contains the read/free functions, use %THIS_MODULE 174833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * @data: data cookie for the @read/@free functions 175833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * @datalen: length of the data 176833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * @gfp: allocation flags 177833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * @read: function to read from the given buffer 178833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * @free: function to free the given buffer 179833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * 180833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * Creates a new device coredump for the given device. If a previous one hasn't 181833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * been read yet, the new coredump is discarded. The data lifetime is determined 182833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * by the device coredump framework and when it is no longer needed the @free 183833c95456a70826d1384883b73fd23aff24d366fJohannes Berg * function will be called to free the data. 184833c95456a70826d1384883b73fd23aff24d366fJohannes Berg */ 185833c95456a70826d1384883b73fd23aff24d366fJohannes Bergvoid dev_coredumpm(struct device *dev, struct module *owner, 186833c95456a70826d1384883b73fd23aff24d366fJohannes Berg const void *data, size_t datalen, gfp_t gfp, 187833c95456a70826d1384883b73fd23aff24d366fJohannes Berg ssize_t (*read)(char *buffer, loff_t offset, size_t count, 188833c95456a70826d1384883b73fd23aff24d366fJohannes Berg const void *data, size_t datalen), 189833c95456a70826d1384883b73fd23aff24d366fJohannes Berg void (*free)(const void *data)) 190833c95456a70826d1384883b73fd23aff24d366fJohannes Berg{ 191833c95456a70826d1384883b73fd23aff24d366fJohannes Berg static atomic_t devcd_count = ATOMIC_INIT(0); 192833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct devcd_entry *devcd; 193833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct device *existing; 194833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 195833c95456a70826d1384883b73fd23aff24d366fJohannes Berg existing = class_find_device(&devcd_class, NULL, dev, 196833c95456a70826d1384883b73fd23aff24d366fJohannes Berg devcd_match_failing); 197833c95456a70826d1384883b73fd23aff24d366fJohannes Berg if (existing) { 198833c95456a70826d1384883b73fd23aff24d366fJohannes Berg put_device(existing); 199833c95456a70826d1384883b73fd23aff24d366fJohannes Berg goto free; 200833c95456a70826d1384883b73fd23aff24d366fJohannes Berg } 201833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 202833c95456a70826d1384883b73fd23aff24d366fJohannes Berg if (!try_module_get(owner)) 203833c95456a70826d1384883b73fd23aff24d366fJohannes Berg goto free; 204833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 205833c95456a70826d1384883b73fd23aff24d366fJohannes Berg devcd = kzalloc(sizeof(*devcd), gfp); 206833c95456a70826d1384883b73fd23aff24d366fJohannes Berg if (!devcd) 207833c95456a70826d1384883b73fd23aff24d366fJohannes Berg goto put_module; 208833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 209833c95456a70826d1384883b73fd23aff24d366fJohannes Berg devcd->owner = owner; 210833c95456a70826d1384883b73fd23aff24d366fJohannes Berg devcd->data = data; 211833c95456a70826d1384883b73fd23aff24d366fJohannes Berg devcd->datalen = datalen; 212833c95456a70826d1384883b73fd23aff24d366fJohannes Berg devcd->read = read; 213833c95456a70826d1384883b73fd23aff24d366fJohannes Berg devcd->free = free; 214833c95456a70826d1384883b73fd23aff24d366fJohannes Berg devcd->failing_dev = get_device(dev); 215833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 216833c95456a70826d1384883b73fd23aff24d366fJohannes Berg device_initialize(&devcd->devcd_dev); 217833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 218833c95456a70826d1384883b73fd23aff24d366fJohannes Berg dev_set_name(&devcd->devcd_dev, "devcd%d", 219833c95456a70826d1384883b73fd23aff24d366fJohannes Berg atomic_inc_return(&devcd_count)); 220833c95456a70826d1384883b73fd23aff24d366fJohannes Berg devcd->devcd_dev.class = &devcd_class; 221833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 222833c95456a70826d1384883b73fd23aff24d366fJohannes Berg if (device_add(&devcd->devcd_dev)) 223833c95456a70826d1384883b73fd23aff24d366fJohannes Berg goto put_device; 224833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 225833c95456a70826d1384883b73fd23aff24d366fJohannes Berg if (sysfs_create_link(&devcd->devcd_dev.kobj, &dev->kobj, 226833c95456a70826d1384883b73fd23aff24d366fJohannes Berg "failing_device")) 227833c95456a70826d1384883b73fd23aff24d366fJohannes Berg /* nothing - symlink will be missing */; 228833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 229833c95456a70826d1384883b73fd23aff24d366fJohannes Berg if (sysfs_create_link(&dev->kobj, &devcd->devcd_dev.kobj, 230833c95456a70826d1384883b73fd23aff24d366fJohannes Berg "devcoredump")) 231833c95456a70826d1384883b73fd23aff24d366fJohannes Berg /* nothing - symlink will be missing */; 232833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 233833c95456a70826d1384883b73fd23aff24d366fJohannes Berg INIT_DELAYED_WORK(&devcd->del_wk, devcd_del); 234833c95456a70826d1384883b73fd23aff24d366fJohannes Berg schedule_delayed_work(&devcd->del_wk, DEVCD_TIMEOUT); 235833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 236833c95456a70826d1384883b73fd23aff24d366fJohannes Berg return; 237833c95456a70826d1384883b73fd23aff24d366fJohannes Berg put_device: 238833c95456a70826d1384883b73fd23aff24d366fJohannes Berg put_device(&devcd->devcd_dev); 239833c95456a70826d1384883b73fd23aff24d366fJohannes Berg put_module: 240833c95456a70826d1384883b73fd23aff24d366fJohannes Berg module_put(owner); 241833c95456a70826d1384883b73fd23aff24d366fJohannes Berg free: 242833c95456a70826d1384883b73fd23aff24d366fJohannes Berg free(data); 243833c95456a70826d1384883b73fd23aff24d366fJohannes Berg} 244833c95456a70826d1384883b73fd23aff24d366fJohannes BergEXPORT_SYMBOL_GPL(dev_coredumpm); 245833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 246833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic int __init devcoredump_init(void) 247833c95456a70826d1384883b73fd23aff24d366fJohannes Berg{ 248833c95456a70826d1384883b73fd23aff24d366fJohannes Berg return class_register(&devcd_class); 249833c95456a70826d1384883b73fd23aff24d366fJohannes Berg} 250833c95456a70826d1384883b73fd23aff24d366fJohannes Berg__initcall(devcoredump_init); 251833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 252833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic int devcd_free(struct device *dev, void *data) 253833c95456a70826d1384883b73fd23aff24d366fJohannes Berg{ 254833c95456a70826d1384883b73fd23aff24d366fJohannes Berg struct devcd_entry *devcd = dev_to_devcd(dev); 255833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 256833c95456a70826d1384883b73fd23aff24d366fJohannes Berg flush_delayed_work(&devcd->del_wk); 257833c95456a70826d1384883b73fd23aff24d366fJohannes Berg return 0; 258833c95456a70826d1384883b73fd23aff24d366fJohannes Berg} 259833c95456a70826d1384883b73fd23aff24d366fJohannes Berg 260833c95456a70826d1384883b73fd23aff24d366fJohannes Bergstatic void __exit devcoredump_exit(void) 261833c95456a70826d1384883b73fd23aff24d366fJohannes Berg{ 262833c95456a70826d1384883b73fd23aff24d366fJohannes Berg class_for_each_device(&devcd_class, NULL, NULL, devcd_free); 263833c95456a70826d1384883b73fd23aff24d366fJohannes Berg class_unregister(&devcd_class); 264833c95456a70826d1384883b73fd23aff24d366fJohannes Berg} 265833c95456a70826d1384883b73fd23aff24d366fJohannes Berg__exitcall(devcoredump_exit); 266