aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2012-05-18 01:59:52 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-13 19:38:40 -0400
commitb02f8bede217a4b145ecc16d3940c78d83941147 (patch)
treecbd02191cc2698c460b9abedea44de13855510c6 /drivers/power
parentb7e938d06d0de43bdbee8844a8736c81480c1031 (diff)
W1: split master mutex to avoid deadlocks.
The 'mutex' in struct w1_master is use for two very different purposes. Firstly it protects various data structures such as the list of all slaves. Secondly it protects the w1 buss against concurrent accesses. This can lead to deadlocks when the ->probe code called while adding a slave needs to talk on the bus, as is the case for power_supply devices. ds2780 and ds2781 drivers contain a work around to track which process hold the lock simply to avoid this deadlock. bq27000 doesn't have that work around and so deadlocks. There are other possible deadlocks involving sysfs. When removing a device the sysfs s_active lock is held, so the lock that protects the slave list must take precedence over s_active. However when access power_supply attributes via sysfs, the s_active lock must take precedence over the lock that protects accesses to the bus. So to avoid deadlocks between w1 slaves and sysfs, these must be two separate locks. Making them separate means that the work around in ds2780 and ds2781 can be removed. So this patch: - adds a new mutex: "bus_mutex" which serialises access to the bus. - takes in mutex in w1_search and ds1wm_search while they access the bus for searching. The mutex is dropped before calling the callback which adds the slave. - changes all slaves to use bus_mutex instead of mutex to protect access to the bus - removes w1_ds2790_io_nolock and w1_ds2781_io_nolock, and the related code from drivers/power/ds278[01]_battery.c which calls them. Signed-off-by: NeilBrown <neilb@suse.de> Acked-by: Evgeniy Polyakov <zbr@ioremap.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/ds2780_battery.c11
-rw-r--r--drivers/power/ds2781_battery.c12
2 files changed, 2 insertions, 21 deletions
diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c
index de31cae1ba53..74fad941c56c 100644
--- a/drivers/power/ds2780_battery.c
+++ b/drivers/power/ds2780_battery.c
@@ -39,7 +39,6 @@ struct ds2780_device_info {
39 struct device *dev; 39 struct device *dev;
40 struct power_supply bat; 40 struct power_supply bat;
41 struct device *w1_dev; 41 struct device *w1_dev;
42 struct task_struct *mutex_holder;
43}; 42};
44 43
45enum current_types { 44enum current_types {
@@ -64,10 +63,7 @@ static inline struct power_supply *to_power_supply(struct device *dev)
64static inline int ds2780_battery_io(struct ds2780_device_info *dev_info, 63static inline int ds2780_battery_io(struct ds2780_device_info *dev_info,
65 char *buf, int addr, size_t count, int io) 64 char *buf, int addr, size_t count, int io)
66{ 65{
67 if (dev_info->mutex_holder == current) 66 return w1_ds2780_io(dev_info->w1_dev, buf, addr, count, io);
68 return w1_ds2780_io_nolock(dev_info->w1_dev, buf, addr, count, io);
69 else
70 return w1_ds2780_io(dev_info->w1_dev, buf, addr, count, io);
71} 67}
72 68
73static inline int ds2780_read8(struct ds2780_device_info *dev_info, u8 *val, 69static inline int ds2780_read8(struct ds2780_device_info *dev_info, u8 *val,
@@ -779,7 +775,6 @@ static int __devinit ds2780_battery_probe(struct platform_device *pdev)
779 dev_info->bat.properties = ds2780_battery_props; 775 dev_info->bat.properties = ds2780_battery_props;
780 dev_info->bat.num_properties = ARRAY_SIZE(ds2780_battery_props); 776 dev_info->bat.num_properties = ARRAY_SIZE(ds2780_battery_props);
781 dev_info->bat.get_property = ds2780_battery_get_property; 777 dev_info->bat.get_property = ds2780_battery_get_property;
782 dev_info->mutex_holder = current;
783 778
784 ret = power_supply_register(&pdev->dev, &dev_info->bat); 779 ret = power_supply_register(&pdev->dev, &dev_info->bat);
785 if (ret) { 780 if (ret) {
@@ -809,8 +804,6 @@ static int __devinit ds2780_battery_probe(struct platform_device *pdev)
809 goto fail_remove_bin_file; 804 goto fail_remove_bin_file;
810 } 805 }
811 806
812 dev_info->mutex_holder = NULL;
813
814 return 0; 807 return 0;
815 808
816fail_remove_bin_file: 809fail_remove_bin_file:
@@ -830,8 +823,6 @@ static int __devexit ds2780_battery_remove(struct platform_device *pdev)
830{ 823{
831 struct ds2780_device_info *dev_info = platform_get_drvdata(pdev); 824 struct ds2780_device_info *dev_info = platform_get_drvdata(pdev);
832 825
833 dev_info->mutex_holder = current;
834
835 /* remove attributes */ 826 /* remove attributes */
836 sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group); 827 sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
837 828
diff --git a/drivers/power/ds2781_battery.c b/drivers/power/ds2781_battery.c
index 975684a40f15..5f92a4bb33f9 100644
--- a/drivers/power/ds2781_battery.c
+++ b/drivers/power/ds2781_battery.c
@@ -37,7 +37,6 @@ struct ds2781_device_info {
37 struct device *dev; 37 struct device *dev;
38 struct power_supply bat; 38 struct power_supply bat;
39 struct device *w1_dev; 39 struct device *w1_dev;
40 struct task_struct *mutex_holder;
41}; 40};
42 41
43enum current_types { 42enum current_types {
@@ -62,11 +61,7 @@ static inline struct power_supply *to_power_supply(struct device *dev)
62static inline int ds2781_battery_io(struct ds2781_device_info *dev_info, 61static inline int ds2781_battery_io(struct ds2781_device_info *dev_info,
63 char *buf, int addr, size_t count, int io) 62 char *buf, int addr, size_t count, int io)
64{ 63{
65 if (dev_info->mutex_holder == current) 64 return w1_ds2781_io(dev_info->w1_dev, buf, addr, count, io);
66 return w1_ds2781_io_nolock(dev_info->w1_dev, buf, addr,
67 count, io);
68 else
69 return w1_ds2781_io(dev_info->w1_dev, buf, addr, count, io);
70} 65}
71 66
72int w1_ds2781_read(struct ds2781_device_info *dev_info, char *buf, 67int w1_ds2781_read(struct ds2781_device_info *dev_info, char *buf,
@@ -775,7 +770,6 @@ static int __devinit ds2781_battery_probe(struct platform_device *pdev)
775 dev_info->bat.properties = ds2781_battery_props; 770 dev_info->bat.properties = ds2781_battery_props;
776 dev_info->bat.num_properties = ARRAY_SIZE(ds2781_battery_props); 771 dev_info->bat.num_properties = ARRAY_SIZE(ds2781_battery_props);
777 dev_info->bat.get_property = ds2781_battery_get_property; 772 dev_info->bat.get_property = ds2781_battery_get_property;
778 dev_info->mutex_holder = current;
779 773
780 ret = power_supply_register(&pdev->dev, &dev_info->bat); 774 ret = power_supply_register(&pdev->dev, &dev_info->bat);
781 if (ret) { 775 if (ret) {
@@ -805,8 +799,6 @@ static int __devinit ds2781_battery_probe(struct platform_device *pdev)
805 goto fail_remove_bin_file; 799 goto fail_remove_bin_file;
806 } 800 }
807 801
808 dev_info->mutex_holder = NULL;
809
810 return 0; 802 return 0;
811 803
812fail_remove_bin_file: 804fail_remove_bin_file:
@@ -826,8 +818,6 @@ static int __devexit ds2781_battery_remove(struct platform_device *pdev)
826{ 818{
827 struct ds2781_device_info *dev_info = platform_get_drvdata(pdev); 819 struct ds2781_device_info *dev_info = platform_get_drvdata(pdev);
828 820
829 dev_info->mutex_holder = current;
830
831 /* remove attributes */ 821 /* remove attributes */
832 sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2781_attr_group); 822 sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2781_attr_group);
833 823