driver-core: extend dev_printk() to pass structured data
authorKay Sievers <kay@vrfy.org>
Thu, 3 May 2012 00:29:59 +0000 (02:29 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 8 May 2012 00:12:03 +0000 (17:12 -0700)
Extends dev_printk() to attach a dictionary with a device identifier
and the driver core subsystem name to logged messages, which makes
dev_prink() reliable machine-readable. In addition to the printed
plain text message, it creates these properties:
    SUBSYSTEM=     - the driver-core subsytem name
    DEVICE=
      b12:8        - block dev_t
      c127:3       - char dev_t
      n8           - netdev ifindex
      +sound:card0 - subsystem:devname

Tested-by: William Douglas <william.douglas@intel.com>
Signed-off-by: Kay Sievers <kay@vrfy.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/base/core.c

index 33461ec35d8f54ce460a6a50844c87146c3ee0a4..346be8b78b247e78fbe987fdfae435f8919cb2c6 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/mutex.h>
 #include <linux/async.h>
 #include <linux/pm_runtime.h>
+#include <linux/netdevice.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -1843,15 +1844,60 @@ void device_shutdown(void)
  */
 
 #ifdef CONFIG_PRINTK
-
 int __dev_printk(const char *level, const struct device *dev,
                 struct va_format *vaf)
 {
+       char dict[128];
+       size_t dictlen = 0;
+       const char *subsys;
+
        if (!dev)
                return printk("%s(NULL device *): %pV", level, vaf);
 
-       return printk("%s%s %s: %pV",
-                     level, dev_driver_string(dev), dev_name(dev), vaf);
+       if (dev->class)
+               subsys = dev->class->name;
+       else if (dev->bus)
+               subsys = dev->bus->name;
+       else
+               goto skip;
+
+       dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+                           "SUBSYSTEM=%s", subsys);
+
+       /*
+        * Add device identifier DEVICE=:
+        *   b12:8         block dev_t
+        *   c127:3        char dev_t
+        *   n8            netdev ifindex
+        *   +sound:card0  subsystem:devname
+        */
+       if (MAJOR(dev->devt)) {
+               char c;
+
+               if (strcmp(subsys, "block") == 0)
+                       c = 'b';
+               else
+                       c = 'c';
+               dictlen++;
+               dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+                                  "DEVICE=%c%u:%u",
+                                  c, MAJOR(dev->devt), MINOR(dev->devt));
+       } else if (strcmp(subsys, "net") == 0) {
+               struct net_device *net = to_net_dev(dev);
+
+               dictlen++;
+               dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+                                   "DEVICE=n%u", net->ifindex);
+       } else {
+               dictlen++;
+               dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+                                   "DEVICE=+%s:%s", subsys, dev_name(dev));
+       }
+skip:
+       return printk_emit(0, level[1] - '0',
+                          dictlen ? dict : NULL, dictlen,
+                          "%s %s: %pV",
+                          dev_driver_string(dev), dev_name(dev), vaf);
 }
 EXPORT_SYMBOL(__dev_printk);