From 3b0d71170d37878bbb1203ebc3f92e36d6151a80 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 23 Jul 2007 11:21:34 +0100 Subject: [PATCH] ACPI: asus-laptop: Fix failure exits > Subject : drivers/misc/asus-laptop.c:*: error: 'struct led_classdev' has no member named 'class_dev' > References : http://lkml.org/lkml/2007/7/22/299 > Submitter : Gabriel C Fallout from f8a7c6fe14f556ca8eeddce258cb21392d0c3a2f. However, looking at it shows that checks done in ASUS_LED_UNREGISTER() can't trigger at all (we never get to asus_led_exit() if registration fails) and if that registration fails, we actually leak stuff. IOW, it's worse than just replacing class_dev with dev in there - the tests themselves had been papering over the lousy cleanup logics. Signed-off-by: Al Viro Signed-off-by: Len Brown --- drivers/misc/asus-laptop.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index f75306059971..6b89854bd3ff 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c @@ -1067,19 +1067,16 @@ static void asus_backlight_exit(void) } #define ASUS_LED_UNREGISTER(object) \ - if(object##_led.class_dev \ - && !IS_ERR(object##_led.class_dev)) \ - led_classdev_unregister(&object##_led) + led_classdev_unregister(&object##_led) static void asus_led_exit(void) { + destroy_workqueue(led_workqueue); ASUS_LED_UNREGISTER(mled); ASUS_LED_UNREGISTER(tled); ASUS_LED_UNREGISTER(pled); ASUS_LED_UNREGISTER(rled); ASUS_LED_UNREGISTER(gled); - - destroy_workqueue(led_workqueue); } static void __exit asus_laptop_exit(void) @@ -1135,29 +1132,42 @@ static int asus_led_init(struct device *dev) rv = ASUS_LED_REGISTER(mled, dev); if (rv) - return rv; + goto out; rv = ASUS_LED_REGISTER(tled, dev); if (rv) - return rv; + goto out1; rv = ASUS_LED_REGISTER(rled, dev); if (rv) - return rv; + goto out2; rv = ASUS_LED_REGISTER(pled, dev); if (rv) - return rv; + goto out3; rv = ASUS_LED_REGISTER(gled, dev); if (rv) - return rv; + goto out4; led_workqueue = create_singlethread_workqueue("led_workqueue"); if (!led_workqueue) - return -ENOMEM; + goto out5; return 0; +out5: + rv = -ENOMEM; + ASUS_LED_UNREGISTER(gled); +out4: + ASUS_LED_UNREGISTER(pled); +out3: + ASUS_LED_UNREGISTER(rled); +out2: + ASUS_LED_UNREGISTER(tled); +out1: + ASUS_LED_UNREGISTER(mled); +out: + return rv; } static int __init asus_laptop_init(void)