Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds

* 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds:
leds: Fix led trigger locking bugs

+30 -28
+3 -3
drivers/leds/led-class.c
··· 111 111 write_unlock(&leds_list_lock); 112 112 113 113 #ifdef CONFIG_LEDS_TRIGGERS 114 - rwlock_init(&led_cdev->trigger_lock); 114 + init_rwsem(&led_cdev->trigger_lock); 115 115 116 116 rc = device_create_file(led_cdev->dev, &dev_attr_trigger); 117 117 if (rc) ··· 147 147 device_remove_file(led_cdev->dev, &dev_attr_brightness); 148 148 #ifdef CONFIG_LEDS_TRIGGERS 149 149 device_remove_file(led_cdev->dev, &dev_attr_trigger); 150 - write_lock(&led_cdev->trigger_lock); 150 + down_write(&led_cdev->trigger_lock); 151 151 if (led_cdev->trigger) 152 152 led_trigger_set(led_cdev, NULL); 153 - write_unlock(&led_cdev->trigger_lock); 153 + up_write(&led_cdev->trigger_lock); 154 154 #endif 155 155 156 156 device_unregister(led_cdev->dev);
+25 -24
drivers/leds/led-triggers.c
··· 19 19 #include <linux/device.h> 20 20 #include <linux/sysdev.h> 21 21 #include <linux/timer.h> 22 + #include <linux/rwsem.h> 22 23 #include <linux/leds.h> 23 24 #include "leds.h" 24 25 25 26 /* 26 27 * Nests outside led_cdev->trigger_lock 27 28 */ 28 - static DEFINE_RWLOCK(triggers_list_lock); 29 + static DECLARE_RWSEM(triggers_list_lock); 29 30 static LIST_HEAD(trigger_list); 30 31 31 32 ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, ··· 45 44 trigger_name[len - 1] = '\0'; 46 45 47 46 if (!strcmp(trigger_name, "none")) { 48 - write_lock(&led_cdev->trigger_lock); 47 + down_write(&led_cdev->trigger_lock); 49 48 led_trigger_set(led_cdev, NULL); 50 - write_unlock(&led_cdev->trigger_lock); 49 + up_write(&led_cdev->trigger_lock); 51 50 return count; 52 51 } 53 52 54 - read_lock(&triggers_list_lock); 53 + down_read(&triggers_list_lock); 55 54 list_for_each_entry(trig, &trigger_list, next_trig) { 56 55 if (!strcmp(trigger_name, trig->name)) { 57 - write_lock(&led_cdev->trigger_lock); 56 + down_write(&led_cdev->trigger_lock); 58 57 led_trigger_set(led_cdev, trig); 59 - write_unlock(&led_cdev->trigger_lock); 58 + up_write(&led_cdev->trigger_lock); 60 59 61 - read_unlock(&triggers_list_lock); 60 + up_read(&triggers_list_lock); 62 61 return count; 63 62 } 64 63 } 65 - read_unlock(&triggers_list_lock); 64 + up_read(&triggers_list_lock); 66 65 67 66 return -EINVAL; 68 67 } ··· 75 74 struct led_trigger *trig; 76 75 int len = 0; 77 76 78 - read_lock(&triggers_list_lock); 79 - read_lock(&led_cdev->trigger_lock); 77 + down_read(&triggers_list_lock); 78 + down_read(&led_cdev->trigger_lock); 80 79 81 80 if (!led_cdev->trigger) 82 81 len += sprintf(buf+len, "[none] "); ··· 90 89 else 91 90 len += sprintf(buf+len, "%s ", trig->name); 92 91 } 93 - read_unlock(&led_cdev->trigger_lock); 94 - read_unlock(&triggers_list_lock); 92 + up_read(&led_cdev->trigger_lock); 93 + up_read(&triggers_list_lock); 95 94 96 95 len += sprintf(len+buf, "\n"); 97 96 return len; ··· 146 145 if (!led_cdev->default_trigger) 147 146 return; 148 147 149 - read_lock(&triggers_list_lock); 150 - write_lock(&led_cdev->trigger_lock); 148 + down_read(&triggers_list_lock); 149 + down_write(&led_cdev->trigger_lock); 151 150 list_for_each_entry(trig, &trigger_list, next_trig) { 152 151 if (!strcmp(led_cdev->default_trigger, trig->name)) 153 152 led_trigger_set(led_cdev, trig); 154 153 } 155 - write_unlock(&led_cdev->trigger_lock); 156 - read_unlock(&triggers_list_lock); 154 + up_write(&led_cdev->trigger_lock); 155 + up_read(&triggers_list_lock); 157 156 } 158 157 159 158 int led_trigger_register(struct led_trigger *trigger) ··· 164 163 INIT_LIST_HEAD(&trigger->led_cdevs); 165 164 166 165 /* Add to the list of led triggers */ 167 - write_lock(&triggers_list_lock); 166 + down_write(&triggers_list_lock); 168 167 list_add_tail(&trigger->next_trig, &trigger_list); 169 - write_unlock(&triggers_list_lock); 168 + up_write(&triggers_list_lock); 170 169 171 170 /* Register with any LEDs that have this as a default trigger */ 172 171 read_lock(&leds_list_lock); 173 172 list_for_each_entry(led_cdev, &leds_list, node) { 174 - write_lock(&led_cdev->trigger_lock); 173 + down_write(&led_cdev->trigger_lock); 175 174 if (!led_cdev->trigger && led_cdev->default_trigger && 176 175 !strcmp(led_cdev->default_trigger, trigger->name)) 177 176 led_trigger_set(led_cdev, trigger); 178 - write_unlock(&led_cdev->trigger_lock); 177 + up_write(&led_cdev->trigger_lock); 179 178 } 180 179 read_unlock(&leds_list_lock); 181 180 ··· 207 206 struct led_classdev *led_cdev; 208 207 209 208 /* Remove from the list of led triggers */ 210 - write_lock(&triggers_list_lock); 209 + down_write(&triggers_list_lock); 211 210 list_del(&trigger->next_trig); 212 - write_unlock(&triggers_list_lock); 211 + up_write(&triggers_list_lock); 213 212 214 213 /* Remove anyone actively using this trigger */ 215 214 read_lock(&leds_list_lock); 216 215 list_for_each_entry(led_cdev, &leds_list, node) { 217 - write_lock(&led_cdev->trigger_lock); 216 + down_write(&led_cdev->trigger_lock); 218 217 if (led_cdev->trigger == trigger) 219 218 led_trigger_set(led_cdev, NULL); 220 - write_unlock(&led_cdev->trigger_lock); 219 + up_write(&led_cdev->trigger_lock); 221 220 } 222 221 read_unlock(&leds_list_lock); 223 222 }
+2 -1
include/linux/leds.h
··· 14 14 15 15 #include <linux/list.h> 16 16 #include <linux/spinlock.h> 17 + #include <linux/rwsem.h> 17 18 18 19 struct device; 19 20 /* ··· 44 43 45 44 #ifdef CONFIG_LEDS_TRIGGERS 46 45 /* Protects the trigger data below */ 47 - rwlock_t trigger_lock; 46 + struct rw_semaphore trigger_lock; 48 47 49 48 struct led_trigger *trigger; 50 49 struct list_head trig_list;