aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/w1
diff options
context:
space:
mode:
authorDavid Fries <david@fries.net>2008-10-16 01:04:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-16 14:21:49 -0400
commitc30c9b15187e977ab5928f7276e9dfcd8d6f9460 (patch)
treed36d7513c5acf1d39f581625ffa5c1915ae5627f /drivers/w1
parentdd78c9439fc1e031835bccb934d27b978c72c536 (diff)
W1: fix deadlocks and remove w1_control_thread
w1_control_thread was removed which would wake up every second and process newly registered family codes and complete some final cleanup for a removed master. Those routines were moved to the threads that were previously requesting those operations. A new function w1_reconnect_slaves takes care of reconnecting existing slave devices when a new family code is registered or removed. The removal case was missing and would cause a deadlock waiting for the family code reference count to decrease, which will now happen. A problem with registering a family code was fixed. A slave device would be unattached if it wasn't yet claimed, then attached at the end of the list, two unclaimed slaves would cause an infinite loop. The struct w1_bus_master.search now takes a pointer to the struct w1_master device to avoid searching for it, which would have caused a lock ordering deadlock with the removal of w1_control_thread. Signed-off-by: David Fries <david@fries.net> Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/w1')
-rw-r--r--drivers/w1/masters/ds1wm.c6
-rw-r--r--drivers/w1/w1.c146
-rw-r--r--drivers/w1/w1.h19
-rw-r--r--drivers/w1/w1_family.c6
-rw-r--r--drivers/w1/w1_family.h1
-rw-r--r--drivers/w1/w1_int.c12
-rw-r--r--drivers/w1/w1_io.c3
7 files changed, 71 insertions, 122 deletions
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c
index 10211e493001..ea894bf18113 100644
--- a/drivers/w1/masters/ds1wm.c
+++ b/drivers/w1/masters/ds1wm.c
@@ -274,8 +274,8 @@ static u8 ds1wm_reset_bus(void *data)
274 return 0; 274 return 0;
275} 275}
276 276
277static void ds1wm_search(void *data, u8 search_type, 277static void ds1wm_search(void *data, struct w1_master *master_dev,
278 w1_slave_found_callback slave_found) 278 u8 search_type, w1_slave_found_callback slave_found)
279{ 279{
280 struct ds1wm_data *ds1wm_data = data; 280 struct ds1wm_data *ds1wm_data = data;
281 int i; 281 int i;
@@ -313,7 +313,7 @@ static void ds1wm_search(void *data, u8 search_type,
313 ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA); 313 ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA);
314 ds1wm_reset(ds1wm_data); 314 ds1wm_reset(ds1wm_data);
315 315
316 slave_found(ds1wm_data, rom_id); 316 slave_found(master_dev, rom_id);
317} 317}
318 318
319/* --------------------------------------------------------------------- */ 319/* --------------------------------------------------------------------- */
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 7293c9b11f91..25640f681729 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -46,20 +46,16 @@ MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
46MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol."); 46MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
47 47
48static int w1_timeout = 10; 48static int w1_timeout = 10;
49static int w1_control_timeout = 1;
50int w1_max_slave_count = 10; 49int w1_max_slave_count = 10;
51int w1_max_slave_ttl = 10; 50int w1_max_slave_ttl = 10;
52 51
53module_param_named(timeout, w1_timeout, int, 0); 52module_param_named(timeout, w1_timeout, int, 0);
54module_param_named(control_timeout, w1_control_timeout, int, 0);
55module_param_named(max_slave_count, w1_max_slave_count, int, 0); 53module_param_named(max_slave_count, w1_max_slave_count, int, 0);
56module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); 54module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
57 55
58DEFINE_MUTEX(w1_mlock); 56DEFINE_MUTEX(w1_mlock);
59LIST_HEAD(w1_masters); 57LIST_HEAD(w1_masters);
60 58
61static struct task_struct *w1_control_thread;
62
63static int w1_master_match(struct device *dev, struct device_driver *drv) 59static int w1_master_match(struct device *dev, struct device_driver *drv)
64{ 60{
65 return 1; 61 return 1;
@@ -390,7 +386,7 @@ int w1_create_master_attributes(struct w1_master *master)
390 return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group); 386 return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group);
391} 387}
392 388
393static void w1_destroy_master_attributes(struct w1_master *master) 389void w1_destroy_master_attributes(struct w1_master *master)
394{ 390{
395 sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group); 391 sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
396} 392}
@@ -567,7 +563,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
567 return 0; 563 return 0;
568} 564}
569 565
570static void w1_slave_detach(struct w1_slave *sl) 566void w1_slave_detach(struct w1_slave *sl)
571{ 567{
572 struct w1_netlink_msg msg; 568 struct w1_netlink_msg msg;
573 569
@@ -591,24 +587,6 @@ static void w1_slave_detach(struct w1_slave *sl)
591 kfree(sl); 587 kfree(sl);
592} 588}
593 589
594static struct w1_master *w1_search_master(void *data)
595{
596 struct w1_master *dev;
597 int found = 0;
598
599 mutex_lock(&w1_mlock);
600 list_for_each_entry(dev, &w1_masters, w1_master_entry) {
601 if (dev->bus_master->data == data) {
602 found = 1;
603 atomic_inc(&dev->refcnt);
604 break;
605 }
606 }
607 mutex_unlock(&w1_mlock);
608
609 return (found)?dev:NULL;
610}
611
612struct w1_master *w1_search_master_id(u32 id) 590struct w1_master *w1_search_master_id(u32 id)
613{ 591{
614 struct w1_master *dev; 592 struct w1_master *dev;
@@ -656,34 +634,49 @@ struct w1_slave *w1_search_slave(struct w1_reg_num *id)
656 return (found)?sl:NULL; 634 return (found)?sl:NULL;
657} 635}
658 636
659void w1_reconnect_slaves(struct w1_family *f) 637void w1_reconnect_slaves(struct w1_family *f, int attach)
660{ 638{
639 struct w1_slave *sl, *sln;
661 struct w1_master *dev; 640 struct w1_master *dev;
662 641
663 mutex_lock(&w1_mlock); 642 mutex_lock(&w1_mlock);
664 list_for_each_entry(dev, &w1_masters, w1_master_entry) { 643 list_for_each_entry(dev, &w1_masters, w1_master_entry) {
665 dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n", 644 dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
666 dev->name, f->fid); 645 "for family %02x.\n", dev->name, f->fid);
667 set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); 646 mutex_lock(&dev->mutex);
647 list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
648 /* If it is a new family, slaves with the default
649 * family driver and are that family will be
650 * connected. If the family is going away, devices
651 * matching that family are reconneced.
652 */
653 if ((attach && sl->family->fid == W1_FAMILY_DEFAULT
654 && sl->reg_num.family == f->fid) ||
655 (!attach && sl->family->fid == f->fid)) {
656 struct w1_reg_num rn;
657
658 memcpy(&rn, &sl->reg_num, sizeof(rn));
659 w1_slave_detach(sl);
660
661 w1_attach_slave_device(dev, &rn);
662 }
663 }
664 dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
665 "has been finished.\n", dev->name);
666 mutex_unlock(&dev->mutex);
668 } 667 }
669 mutex_unlock(&w1_mlock); 668 mutex_unlock(&w1_mlock);
670} 669}
671 670
672static void w1_slave_found(void *data, u64 rn) 671static void w1_slave_found(struct w1_master *dev, u64 rn)
673{ 672{
674 int slave_count; 673 int slave_count;
675 struct w1_slave *sl; 674 struct w1_slave *sl;
676 struct list_head *ent; 675 struct list_head *ent;
677 struct w1_reg_num *tmp; 676 struct w1_reg_num *tmp;
678 struct w1_master *dev;
679 u64 rn_le = cpu_to_le64(rn); 677 u64 rn_le = cpu_to_le64(rn);
680 678
681 dev = w1_search_master(data); 679 atomic_inc(&dev->refcnt);
682 if (!dev) {
683 printk(KERN_ERR "Failed to find w1 master device for data %p, "
684 "it is impossible.\n", data);
685 return;
686 }
687 680
688 tmp = (struct w1_reg_num *) &rn; 681 tmp = (struct w1_reg_num *) &rn;
689 682
@@ -785,76 +778,11 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
785 if ( (desc_bit == last_zero) || (last_zero < 0)) 778 if ( (desc_bit == last_zero) || (last_zero < 0))
786 last_device = 1; 779 last_device = 1;
787 desc_bit = last_zero; 780 desc_bit = last_zero;
788 cb(dev->bus_master->data, rn); 781 cb(dev, rn);
789 } 782 }
790 } 783 }
791} 784}
792 785
793static int w1_control(void *data)
794{
795 struct w1_slave *sl, *sln;
796 struct w1_master *dev, *n;
797 int have_to_wait = 0;
798
799 set_freezable();
800 while (!kthread_should_stop() || have_to_wait) {
801 have_to_wait = 0;
802
803 try_to_freeze();
804 msleep_interruptible(w1_control_timeout * 1000);
805
806 list_for_each_entry_safe(dev, n, &w1_masters, w1_master_entry) {
807 if (!kthread_should_stop() && !dev->flags)
808 continue;
809 /*
810 * Little race: we can create thread but not set the flag.
811 * Get a chance for external process to set flag up.
812 */
813 if (!dev->initialized) {
814 have_to_wait = 1;
815 continue;
816 }
817
818 if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
819 set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
820
821 mutex_lock(&w1_mlock);
822 list_del(&dev->w1_master_entry);
823 mutex_unlock(&w1_mlock);
824
825 mutex_lock(&dev->mutex);
826 list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
827 w1_slave_detach(sl);
828 }
829 w1_destroy_master_attributes(dev);
830 mutex_unlock(&dev->mutex);
831 atomic_dec(&dev->refcnt);
832 continue;
833 }
834
835 if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) {
836 dev_dbg(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name);
837 mutex_lock(&dev->mutex);
838 list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
839 if (sl->family->fid == W1_FAMILY_DEFAULT) {
840 struct w1_reg_num rn;
841
842 memcpy(&rn, &sl->reg_num, sizeof(rn));
843 w1_slave_detach(sl);
844
845 w1_attach_slave_device(dev, &rn);
846 }
847 }
848 dev_dbg(&dev->dev, "Reconnecting slaves in device %s has been finished.\n", dev->name);
849 clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
850 mutex_unlock(&dev->mutex);
851 }
852 }
853 }
854
855 return 0;
856}
857
858void w1_search_process(struct w1_master *dev, u8 search_type) 786void w1_search_process(struct w1_master *dev, u8 search_type)
859{ 787{
860 struct w1_slave *sl, *sln; 788 struct w1_slave *sl, *sln;
@@ -932,18 +860,13 @@ static int w1_init(void)
932 goto err_out_master_unregister; 860 goto err_out_master_unregister;
933 } 861 }
934 862
935 w1_control_thread = kthread_run(w1_control, NULL, "w1_control");
936 if (IS_ERR(w1_control_thread)) {
937 retval = PTR_ERR(w1_control_thread);
938 printk(KERN_ERR "Failed to create control thread. err=%d\n",
939 retval);
940 goto err_out_slave_unregister;
941 }
942
943 return 0; 863 return 0;
944 864
865#if 0
866/* For undoing the slave register if there was a step after it. */
945err_out_slave_unregister: 867err_out_slave_unregister:
946 driver_unregister(&w1_slave_driver); 868 driver_unregister(&w1_slave_driver);
869#endif
947 870
948err_out_master_unregister: 871err_out_master_unregister:
949 driver_unregister(&w1_master_driver); 872 driver_unregister(&w1_master_driver);
@@ -959,13 +882,12 @@ static void w1_fini(void)
959{ 882{
960 struct w1_master *dev; 883 struct w1_master *dev;
961 884
885 /* Set netlink removal messages and some cleanup */
962 list_for_each_entry(dev, &w1_masters, w1_master_entry) 886 list_for_each_entry(dev, &w1_masters, w1_master_entry)
963 __w1_remove_master_device(dev); 887 __w1_remove_master_device(dev);
964 888
965 w1_fini_netlink(); 889 w1_fini_netlink();
966 890
967 kthread_stop(w1_control_thread);
968
969 driver_unregister(&w1_slave_driver); 891 driver_unregister(&w1_slave_driver);
970 driver_unregister(&w1_master_driver); 892 driver_unregister(&w1_master_driver);
971 bus_unregister(&w1_bus_type); 893 bus_unregister(&w1_bus_type);
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h
index f1df5343f4ad..13e0ea880bf8 100644
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -77,7 +77,7 @@ struct w1_slave
77 struct completion released; 77 struct completion released;
78}; 78};
79 79
80typedef void (* w1_slave_found_callback)(void *, u64); 80typedef void (*w1_slave_found_callback)(struct w1_master *, u64);
81 81
82 82
83/** 83/**
@@ -142,12 +142,14 @@ struct w1_bus_master
142 */ 142 */
143 u8 (*reset_bus)(void *); 143 u8 (*reset_bus)(void *);
144 144
145 /** Really nice hardware can handles the different types of ROM search */ 145 /** Really nice hardware can handles the different types of ROM search
146 void (*search)(void *, u8, w1_slave_found_callback); 146 * w1_master* is passed to the slave found callback.
147 */
148 void (*search)(void *, struct w1_master *,
149 u8, w1_slave_found_callback);
147}; 150};
148 151
149#define W1_MASTER_NEED_EXIT 0 152#define W1_MASTER_NEED_EXIT 0
150#define W1_MASTER_NEED_RECONNECT 1
151 153
152struct w1_master 154struct w1_master
153{ 155{
@@ -181,12 +183,21 @@ struct w1_master
181}; 183};
182 184
183int w1_create_master_attributes(struct w1_master *); 185int w1_create_master_attributes(struct w1_master *);
186void w1_destroy_master_attributes(struct w1_master *master);
184void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb); 187void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb);
185void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb); 188void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb);
186struct w1_slave *w1_search_slave(struct w1_reg_num *id); 189struct w1_slave *w1_search_slave(struct w1_reg_num *id);
187void w1_search_process(struct w1_master *dev, u8 search_type); 190void w1_search_process(struct w1_master *dev, u8 search_type);
188struct w1_master *w1_search_master_id(u32 id); 191struct w1_master *w1_search_master_id(u32 id);
189 192
193/* Disconnect and reconnect devices in the given family. Used for finding
194 * unclaimed devices after a family has been registered or releasing devices
195 * after a family has been unregistered. Set attach to 1 when a new family
196 * has just been registered, to 0 when it has been unregistered.
197 */
198void w1_reconnect_slaves(struct w1_family *f, int attach);
199void w1_slave_detach(struct w1_slave *sl);
200
190u8 w1_triplet(struct w1_master *dev, int bdir); 201u8 w1_triplet(struct w1_master *dev, int bdir);
191void w1_write_8(struct w1_master *, u8); 202void w1_write_8(struct w1_master *, u8);
192int w1_reset_bus(struct w1_master *); 203int w1_reset_bus(struct w1_master *);
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c
index a3c95bd6890a..8c35f9ccb689 100644
--- a/drivers/w1/w1_family.c
+++ b/drivers/w1/w1_family.c
@@ -53,7 +53,8 @@ int w1_register_family(struct w1_family *newf)
53 } 53 }
54 spin_unlock(&w1_flock); 54 spin_unlock(&w1_flock);
55 55
56 w1_reconnect_slaves(newf); 56 /* check default devices against the new set of drivers */
57 w1_reconnect_slaves(newf, 1);
57 58
58 return ret; 59 return ret;
59} 60}
@@ -77,6 +78,9 @@ void w1_unregister_family(struct w1_family *fent)
77 78
78 spin_unlock(&w1_flock); 79 spin_unlock(&w1_flock);
79 80
81 /* deatch devices using this family code */
82 w1_reconnect_slaves(fent, 0);
83
80 while (atomic_read(&fent->refcnt)) { 84 while (atomic_read(&fent->refcnt)) {
81 printk(KERN_INFO "Waiting for family %u to become free: refcnt=%d.\n", 85 printk(KERN_INFO "Waiting for family %u to become free: refcnt=%d.\n",
82 fent->fid, atomic_read(&fent->refcnt)); 86 fent->fid, atomic_read(&fent->refcnt));
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index ef1e1dafa19a..296a87edd922 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -63,6 +63,5 @@ void __w1_family_get(struct w1_family *);
63struct w1_family * w1_family_registered(u8); 63struct w1_family * w1_family_registered(u8);
64void w1_unregister_family(struct w1_family *); 64void w1_unregister_family(struct w1_family *);
65int w1_register_family(struct w1_family *); 65int w1_register_family(struct w1_family *);
66void w1_reconnect_slaves(struct w1_family *f);
67 66
68#endif /* __W1_FAMILY_H */ 67#endif /* __W1_FAMILY_H */
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 6840dfebe4d4..ed3228017dad 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -148,10 +148,22 @@ err_out_free_dev:
148void __w1_remove_master_device(struct w1_master *dev) 148void __w1_remove_master_device(struct w1_master *dev)
149{ 149{
150 struct w1_netlink_msg msg; 150 struct w1_netlink_msg msg;
151 struct w1_slave *sl, *sln;
151 152
152 set_bit(W1_MASTER_NEED_EXIT, &dev->flags); 153 set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
153 kthread_stop(dev->thread); 154 kthread_stop(dev->thread);
154 155
156 mutex_lock(&w1_mlock);
157 list_del(&dev->w1_master_entry);
158 mutex_unlock(&w1_mlock);
159
160 mutex_lock(&dev->mutex);
161 list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry)
162 w1_slave_detach(sl);
163 w1_destroy_master_attributes(dev);
164 mutex_unlock(&dev->mutex);
165 atomic_dec(&dev->refcnt);
166
155 while (atomic_read(&dev->refcnt)) { 167 while (atomic_read(&dev->refcnt)) {
156 dev_info(&dev->dev, "Waiting for %s to become free: refcnt=%d.\n", 168 dev_info(&dev->dev, "Waiting for %s to become free: refcnt=%d.\n",
157 dev->name, atomic_read(&dev->refcnt)); 169 dev->name, atomic_read(&dev->refcnt));
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
index 30b6fbf83bd4..0056ef69009b 100644
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -277,7 +277,8 @@ void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_cal
277{ 277{
278 dev->attempts++; 278 dev->attempts++;
279 if (dev->bus_master->search) 279 if (dev->bus_master->search)
280 dev->bus_master->search(dev->bus_master->data, search_type, cb); 280 dev->bus_master->search(dev->bus_master->data, dev,
281 search_type, cb);
281 else 282 else
282 w1_search(dev, search_type, cb); 283 w1_search(dev, search_type, cb);
283} 284}