OSDN Git Service

drivers: base: add coredump driver ops
authorArend van Spriel <aspriel@gmail.com>
Thu, 11 Jan 2018 08:36:38 +0000 (09:36 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 23 Jan 2018 08:47:05 +0000 (09:47 +0100)
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>
drivers/base/dd.c
include/linux/device.h

index 533c82f..de6fd09 100644 (file)
@@ -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");
        }
index 46cece5..cd3b47e 100644 (file)
@@ -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 {