[PATCH V2 2/3] drivers: base: add coredump driver ops

From: Arend van Spriel
Date: Wed Jan 10 2018 - 08:54:27 EST


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. Instead of obtaining raw coredump data from
the driver it is left to the coredump driver operation to invoke
the devcoredump API as there are more ways to do that.

Signed-off-by: Arend van Spriel <aspriel@xxxxxxxxx>
---
V2:
- extended the commit message.
---
drivers/base/dd.c | 40 +++++++++++++++++++++++++++++++++-------
include/linux/device.h | 2 +-
2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 533c82f..de6fd09 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -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");
}
diff --git a/include/linux/device.h b/include/linux/device.h
index 46cece5..cd3b47e 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -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 {
--
1.9.1