From a525a3ddeaca69f405d98442ab3c0746e53168dc Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 25 Jul 2012 01:42:29 +0800 Subject: driver core: free devres in device_release device_del can happen anytime, so once it happens, the devres of the device will be freed inside device_del, but drivers can't know it has been deleted and may still add resources into the device, so memory leak is caused. This patch moves the devres_release_all to fix the problem. Signed-off-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/base/core.c') diff --git a/drivers/base/core.c b/drivers/base/core.c index f338037a4f3d..c8fe4a563866 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -184,6 +184,17 @@ static void device_release(struct kobject *kobj) struct device *dev = kobj_to_dev(kobj); struct device_private *p = dev->p; + /* + * Some platform devices are driven without driver attached + * and managed resources may have been acquired. Make sure + * all resources are released. + * + * Drivers still can add resources into device after device + * is deleted but alive, so release devres here to avoid + * possible memory leak. + */ + devres_release_all(dev); + if (dev->release) dev->release(dev); else if (dev->type && dev->type->release) @@ -1196,13 +1207,6 @@ void device_del(struct device *dev) bus_remove_device(dev); driver_deferred_probe_del(dev); - /* - * Some platform devices are driven without driver attached - * and managed resources may have been acquired. Make sure - * all resources are released. - */ - devres_release_all(dev); - /* Notify the platform of the removal, in case they * need to do anything... */ -- cgit v1.2.3 From 798efc60e4276825df34af0e91ecbe0781237834 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Sep 2012 20:11:29 -0700 Subject: dev_dbg/dynamic_debug: Update to use printk_emit, optimize stack commit c4e00daaa9 ("driver-core: extend dev_printk() to pass structured data") changed __dev_printk and broke dynamic-debug's ability to control the dynamic prefix of dev_dbg(dev,..). commit af7f2158fd ("drivers-core: make structured logging play nice with dynamic-debug") made a minimal correction. The current dynamic debug code uses up to 3 recursion levels via %pV. This can consume quite a bit of stack. Directly call printk_emit to reduce the recursion depth. These changes include: dev_dbg: o Create and use function create_syslog_header to format the syslog header for printk_emit uses. o Call create_syslog_header and neaten __dev_printk o Make __dev_printk static not global o Remove include header declaration of __dev_printk o Remove now unused EXPORT_SYMBOL() of __dev_printk o Whitespace neatening dynamic_dev_dbg: o Remove KERN_DEBUG from dynamic_emit_prefix o Call create_syslog_header and printk_emit o Whitespace neatening Signed-off-by: Joe Perches Acked-by: David S. Miller Tested-by: Jim Cromie Acked-by: Jason Baron Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 64 ++++++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 30 deletions(-) (limited to 'drivers/base/core.c') diff --git a/drivers/base/core.c b/drivers/base/core.c index 91478bd35418..d325b9dab3ff 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1865,26 +1865,19 @@ void device_shutdown(void) */ #ifdef CONFIG_PRINTK -int __dev_printk(const char *level, const struct device *dev, - struct va_format *vaf) +int create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen) { - char dict[128]; - const char *level_extra = ""; - size_t dictlen = 0; const char *subsys; - - if (!dev) - return printk("%s(NULL device *): %pV", level, vaf); + size_t pos = 0; if (dev->class) subsys = dev->class->name; else if (dev->bus) subsys = dev->bus->name; else - goto skip; + return 0; - dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen, - "SUBSYSTEM=%s", subsys); + pos += snprintf(hdr + pos, hdrlen - pos, "SUBSYSTEM=%s", subsys); /* * Add device identifier DEVICE=: @@ -1900,32 +1893,41 @@ int __dev_printk(const char *level, const struct device *dev, c = 'b'; else c = 'c'; - dictlen++; - dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen, - "DEVICE=%c%u:%u", - c, MAJOR(dev->devt), MINOR(dev->devt)); + pos++; + pos += snprintf(hdr + pos, hdrlen - pos, + "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); + pos++; + pos += snprintf(hdr + pos, hdrlen - pos, + "DEVICE=n%u", net->ifindex); } else { - dictlen++; - dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen, - "DEVICE=+%s:%s", subsys, dev_name(dev)); + pos++; + pos += snprintf(hdr + pos, hdrlen - pos, + "DEVICE=+%s:%s", subsys, dev_name(dev)); } -skip: - if (level[2]) - level_extra = &level[2]; /* skip past KERN_SOH "L" */ - return printk_emit(0, level[1] - '0', - dictlen ? dict : NULL, dictlen, - "%s %s: %s%pV", - dev_driver_string(dev), dev_name(dev), - level_extra, vaf); + return pos; +} +EXPORT_SYMBOL(create_syslog_header); + +static int __dev_printk(const char *level, const struct device *dev, + struct va_format *vaf) +{ + char hdr[128]; + size_t hdrlen; + + if (!dev) + return printk("%s(NULL device *): %pV", level, vaf); + + hdrlen = create_syslog_header(dev, hdr, sizeof(hdr)); + + return printk_emit(0, level[1] - '0', hdrlen ? hdr : NULL, hdrlen, + "%s %s: %pV", + dev_driver_string(dev), dev_name(dev), vaf); } -EXPORT_SYMBOL(__dev_printk); int dev_printk(const char *level, const struct device *dev, const char *fmt, ...) @@ -1940,6 +1942,7 @@ int dev_printk(const char *level, const struct device *dev, vaf.va = &args; r = __dev_printk(level, dev, &vaf); + va_end(args); return r; @@ -1959,6 +1962,7 @@ int func(const struct device *dev, const char *fmt, ...) \ vaf.va = &args; \ \ r = __dev_printk(kern_level, dev, &vaf); \ + \ va_end(args); \ \ return r; \ -- cgit v1.2.3 From 05e4e5b87aab74f994acf9dd4bed4a8f1367cd09 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Sep 2012 20:13:37 -0700 Subject: dev: Add dev_vprintk_emit and dev_printk_emit Add utility functions to consolidate the use of create_syslog_header and vprintk_emit. This allows conversion of logging functions that call create_syslog_header and then call vprintk_emit or printk_emit to the dev_ equivalents. Signed-off-by: Joe Perches Acked-by: David S. Miller Tested-by: Jim Cromie Acked-by: Jason Baron Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers/base/core.c') diff --git a/drivers/base/core.c b/drivers/base/core.c index d325b9dab3ff..dff94c8fb350 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1913,6 +1913,33 @@ int create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen) } EXPORT_SYMBOL(create_syslog_header); +int dev_vprintk_emit(int level, const struct device *dev, + const char *fmt, va_list args) +{ + char hdr[128]; + size_t hdrlen; + + hdrlen = create_syslog_header(dev, hdr, sizeof(hdr)); + + return vprintk_emit(0, level, hdrlen ? hdr : NULL, hdrlen, fmt, args); +} +EXPORT_SYMBOL(dev_vprintk_emit); + +int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...) +{ + va_list args; + int r; + + va_start(args, fmt); + + r = dev_vprintk_emit(level, dev, fmt, args); + + va_end(args); + + return r; +} +EXPORT_SYMBOL(dev_printk_emit); + static int __dev_printk(const char *level, const struct device *dev, struct va_format *vaf) { -- cgit v1.2.3 From 666f355f3805d68b6ed5f7013806f1f65abfbf03 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Sep 2012 20:14:11 -0700 Subject: device and dynamic_debug: Use dev_vprintk_emit and dev_printk_emit Convert direct calls of vprintk_emit and printk_emit to the dev_ equivalents. Make create_syslog_header static. Signed-off-by: Joe Perches Acked-by: David S. Miller Tested-by: Jim Cromie Acked-by: Jason Baron Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers/base/core.c') diff --git a/drivers/base/core.c b/drivers/base/core.c index dff94c8fb350..abea76c36a4b 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1865,7 +1865,8 @@ void device_shutdown(void) */ #ifdef CONFIG_PRINTK -int create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen) +static int +create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen) { const char *subsys; size_t pos = 0; @@ -1943,17 +1944,12 @@ EXPORT_SYMBOL(dev_printk_emit); static int __dev_printk(const char *level, const struct device *dev, struct va_format *vaf) { - char hdr[128]; - size_t hdrlen; - if (!dev) return printk("%s(NULL device *): %pV", level, vaf); - hdrlen = create_syslog_header(dev, hdr, sizeof(hdr)); - - return printk_emit(0, level[1] - '0', hdrlen ? hdr : NULL, hdrlen, - "%s %s: %pV", - dev_driver_string(dev), dev_name(dev), vaf); + return dev_printk_emit(level[1] - '0', dev, + "%s %s: %pV", + dev_driver_string(dev), dev_name(dev), vaf); } int dev_printk(const char *level, const struct device *dev, -- cgit v1.2.3