drivers: base: add coredump driver ops
This adds the coredump driver operation. When the driver defines it a coredump file is added in the sysfs folder of the device upon driver binding. The file is removed when the driver is unbound. User-space can trigger a coredump for this device by echo'ing to the coredump file. Signed-off-by: Arend van Spriel <aspriel@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
36d1d09af1
commit
3c47d19ff4
2 changed files with 34 additions and 8 deletions
|
@ -288,6 +288,18 @@ static void driver_bound(struct device *dev)
|
|||
kobject_uevent(&dev->kobj, KOBJ_BIND);
|
||||
}
|
||||
|
||||
static ssize_t coredump_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
device_lock(dev);
|
||||
if (dev->driver->coredump)
|
||||
dev->driver->coredump(dev);
|
||||
device_unlock(dev);
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_WO(coredump);
|
||||
|
||||
static int driver_sysfs_add(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
@ -297,14 +309,26 @@ static int driver_sysfs_add(struct device *dev)
|
|||
BUS_NOTIFY_BIND_DRIVER, dev);
|
||||
|
||||
ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
|
||||
kobject_name(&dev->kobj));
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
|
||||
"driver");
|
||||
if (ret)
|
||||
goto rm_dev;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_DEV_COREDUMP) || !dev->driver->coredump ||
|
||||
!device_create_file(dev, &dev_attr_coredump))
|
||||
return 0;
|
||||
|
||||
sysfs_remove_link(&dev->kobj, "driver");
|
||||
|
||||
rm_dev:
|
||||
sysfs_remove_link(&dev->driver->p->kobj,
|
||||
kobject_name(&dev->kobj));
|
||||
if (ret == 0) {
|
||||
ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
|
||||
"driver");
|
||||
if (ret)
|
||||
sysfs_remove_link(&dev->driver->p->kobj,
|
||||
kobject_name(&dev->kobj));
|
||||
}
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -313,6 +337,8 @@ static void driver_sysfs_remove(struct device *dev)
|
|||
struct device_driver *drv = dev->driver;
|
||||
|
||||
if (drv) {
|
||||
if (drv->coredump)
|
||||
device_remove_file(dev, &dev_attr_coredump);
|
||||
sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj));
|
||||
sysfs_remove_link(&dev->kobj, "driver");
|
||||
}
|
||||
|
|
|
@ -287,6 +287,7 @@ struct device_driver {
|
|||
const struct attribute_group **groups;
|
||||
|
||||
const struct dev_pm_ops *pm;
|
||||
int (*coredump) (struct device *dev);
|
||||
|
||||
struct driver_private *p;
|
||||
};
|
||||
|
@ -300,7 +301,6 @@ extern struct device_driver *driver_find(const char *name,
|
|||
extern int driver_probe_done(void);
|
||||
extern void wait_for_device_probe(void);
|
||||
|
||||
|
||||
/* sysfs interface for exporting driver attributes */
|
||||
|
||||
struct driver_attribute {
|
||||
|
|
Loading…
Reference in a new issue