ar9170: cancel led worker properly on exit
authorChristian Lamparter <chunkeey@web.de>
Mon, 1 Jun 2009 20:49:25 +0000 (22:49 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 3 Jun 2009 18:05:15 +0000 (14:05 -0400)
"[PATCH 3/4 v2] ar9170: fix LED power state handling" revealed
a bug which can cause a ugly crash.

The delayed worker is canceled before the LED class functions are
unregistered... So, if something manages to update the LEDs
while unregister routine is running the timer could fire _after_ the
module has been unloaded.

Signed-off-by: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ar9170/led.c

index 3c8a5728920dde76e8dc87df0160a9a5db1d4711..63fda6cd2101776fa5698eb3a1f5b5601cfb0ed9 100644 (file)
@@ -74,7 +74,7 @@ static void ar9170_update_leds(struct work_struct *work)
 
        mutex_lock(&ar->mutex);
        for (i = 0; i < AR9170_NUM_LEDS; i++)
-               if (ar->leds[i].toggled) {
+               if (ar->leds[i].registered && ar->leds[i].toggled) {
                        led_val |= 1 << i;
 
                        tmp = 70 + 200 / (ar->leds[i].toggled);
@@ -101,6 +101,9 @@ static void ar9170_led_brightness_set(struct led_classdev *led,
        struct ar9170_led *arl = container_of(led, struct ar9170_led, l);
        struct ar9170 *ar = arl->ar;
 
+       if (unlikely(!arl->registered))
+               return ;
+
        if (arl->last_state != !!brightness) {
                arl->toggled++;
                arl->last_state = !!brightness;
@@ -139,13 +142,14 @@ void ar9170_unregister_leds(struct ar9170 *ar)
 {
        int i;
 
-       cancel_delayed_work_sync(&ar->led_work);
-
        for (i = 0; i < AR9170_NUM_LEDS; i++)
                if (ar->leds[i].registered) {
                        led_classdev_unregister(&ar->leds[i].l);
                        ar->leds[i].registered = false;
+                       ar->leds[i].toggled = 0;
                }
+
+       cancel_delayed_work_sync(&ar->led_work);
 }
 
 int ar9170_register_leds(struct ar9170 *ar)