leds-twl4030-pwm: fix another race
authorGrazvydas Ignotas <notasas@gmail.com>
Sat, 19 Mar 2016 01:28:14 +0000 (03:28 +0200)
committerGrazvydas Ignotas <notasas@gmail.com>
Sat, 19 Mar 2016 17:37:59 +0000 (19:37 +0200)
This is a race between twl4030_pwmled_work() reading led->new_brightness
vs twl4030_pwmled_brightness() writing to it. Probably needs a proper
lock, but we want twl4030_pwmled_brightness() to not block and assume
work items come from single queue and should not race each other.

drivers/leds/leds-twl4030-pwm.c

index f6d656e..66f431d 100644 (file)
@@ -99,18 +99,20 @@ static void twl4030_enable_pwm01(enum twl4030_led led, bool enable)
 
 static void twl4030_pwmled_work(struct work_struct *work)
 {
+       enum led_brightness new_brightness;
        struct twl4030_pwmled *led;
        int val;
 
        led = container_of(work, struct twl4030_pwmled, work);
 
-       if (led->new_brightness == LED_OFF) {
+       new_brightness = ACCESS_ONCE(led->new_brightness);
+       if (new_brightness == LED_OFF) {
                if (led->old_brightness != LED_OFF)
                        led->enable(led->id, 0);
                goto out;
        }
 
-       val = led->new_brightness * 0x7f / LED_FULL;
+       val = new_brightness * 0x7f / LED_FULL;
        /* avoid 0: on = off = 0 means full brightness */
        if (val == 0)
                val = 1;
@@ -121,7 +123,7 @@ static void twl4030_pwmled_work(struct work_struct *work)
                led->enable(led->id, 1);
 
 out:
-       led->old_brightness = led->new_brightness;
+       led->old_brightness = new_brightness;
 }
 
 static void twl4030_pwmled_brightness(struct led_classdev *cdev,