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