diff options
author | Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 2005-08-11 09:27:50 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-09-08 17:41:26 -0400 |
commit | 3aca692d3ec7cf89da4575f598e41f74502b22d7 (patch) | |
tree | 84740dbcf1ea648b303020f2106e7f9e46f92835 | |
parent | d2a4ef6a0ce4d841293b49bf2cdc17a0ebfaaf9d (diff) |
[PATCH] w1: Detouching bug fixed.
Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/w1/w1.c | 93 | ||||
-rw-r--r-- | drivers/w1/w1.h | 3 | ||||
-rw-r--r-- | drivers/w1/w1_int.c | 6 |
3 files changed, 51 insertions, 51 deletions
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index e592ca2edd49..4e98ab1aa2f2 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -45,10 +45,12 @@ MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); | |||
45 | MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol."); | 45 | MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol."); |
46 | 46 | ||
47 | static int w1_timeout = 10; | 47 | static int w1_timeout = 10; |
48 | static int w1_control_timeout = 1; | ||
48 | int w1_max_slave_count = 10; | 49 | int w1_max_slave_count = 10; |
49 | int w1_max_slave_ttl = 10; | 50 | int w1_max_slave_ttl = 10; |
50 | 51 | ||
51 | module_param_named(timeout, w1_timeout, int, 0); | 52 | module_param_named(timeout, w1_timeout, int, 0); |
53 | module_param_named(control_timeout, w1_control_timeout, int, 0); | ||
52 | module_param_named(max_slave_count, w1_max_slave_count, int, 0); | 54 | module_param_named(max_slave_count, w1_max_slave_count, int, 0); |
53 | module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); | 55 | module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); |
54 | 56 | ||
@@ -69,37 +71,51 @@ static int w1_master_probe(struct device *dev) | |||
69 | return -ENODEV; | 71 | return -ENODEV; |
70 | } | 72 | } |
71 | 73 | ||
72 | static int w1_master_remove(struct device *dev) | ||
73 | { | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static void w1_master_release(struct device *dev) | 74 | static void w1_master_release(struct device *dev) |
78 | { | 75 | { |
79 | struct w1_master *md = dev_to_w1_master(dev); | 76 | struct w1_master *md = dev_to_w1_master(dev); |
80 | complete(&md->dev_released); | 77 | |
78 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name); | ||
79 | |||
80 | if (md->nls && md->nls->sk_socket) | ||
81 | sock_release(md->nls->sk_socket); | ||
82 | memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master)); | ||
83 | kfree(md); | ||
81 | } | 84 | } |
82 | 85 | ||
83 | static void w1_slave_release(struct device *dev) | 86 | static void w1_slave_release(struct device *dev) |
84 | { | 87 | { |
85 | struct w1_slave *sl = dev_to_w1_slave(dev); | 88 | struct w1_slave *sl = dev_to_w1_slave(dev); |
86 | complete(&sl->dev_released); | 89 | |
90 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name); | ||
91 | |||
92 | while (atomic_read(&sl->refcnt)) { | ||
93 | dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n", | ||
94 | sl->name, atomic_read(&sl->refcnt)); | ||
95 | if (msleep_interruptible(1000)) | ||
96 | flush_signals(current); | ||
97 | } | ||
98 | |||
99 | w1_family_put(sl->family); | ||
100 | sl->master->slave_count--; | ||
101 | |||
102 | complete(&sl->released); | ||
87 | } | 103 | } |
88 | 104 | ||
89 | static ssize_t w1_slave_read_name(struct device *dev, struct device_attribute *attr, char *buf) | 105 | static ssize_t w1_slave_read_name(struct device *dev, struct device_attribute *attr, char *buf) |
90 | { | 106 | { |
91 | struct w1_slave *sl = dev_to_w1_slave(dev); | 107 | struct w1_slave *sl = dev_to_w1_slave(dev); |
92 | 108 | ||
93 | return sprintf(buf, "%s\n", sl->name); | 109 | return sprintf(buf, "%s\n", sl->name); |
94 | } | 110 | } |
95 | 111 | ||
96 | static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, size_t count) | 112 | static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, size_t count) |
97 | { | 113 | { |
98 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | 114 | struct w1_slave *sl = kobj_to_w1_slave(kobj); |
99 | 115 | ||
100 | atomic_inc(&sl->refcnt); | 116 | atomic_inc(&sl->refcnt); |
101 | if (off > 8) { | 117 | if (off > 8) { |
102 | count = 0; | 118 | count = 0; |
103 | } else { | 119 | } else { |
104 | if (off + count > 8) | 120 | if (off + count > 8) |
105 | count = 8 - off; | 121 | count = 8 - off; |
@@ -109,7 +125,7 @@ static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, siz | |||
109 | atomic_dec(&sl->refcnt); | 125 | atomic_dec(&sl->refcnt); |
110 | 126 | ||
111 | return count; | 127 | return count; |
112 | } | 128 | } |
113 | 129 | ||
114 | static struct device_attribute w1_slave_attr_name = | 130 | static struct device_attribute w1_slave_attr_name = |
115 | __ATTR(name, S_IRUGO, w1_slave_read_name, NULL); | 131 | __ATTR(name, S_IRUGO, w1_slave_read_name, NULL); |
@@ -139,7 +155,6 @@ struct device_driver w1_master_driver = { | |||
139 | .name = "w1_master_driver", | 155 | .name = "w1_master_driver", |
140 | .bus = &w1_bus_type, | 156 | .bus = &w1_bus_type, |
141 | .probe = w1_master_probe, | 157 | .probe = w1_master_probe, |
142 | .remove = w1_master_remove, | ||
143 | }; | 158 | }; |
144 | 159 | ||
145 | struct device w1_master_device = { | 160 | struct device w1_master_device = { |
@@ -160,6 +175,7 @@ struct device w1_slave_device = { | |||
160 | .bus = &w1_bus_type, | 175 | .bus = &w1_bus_type, |
161 | .bus_id = "w1 bus slave", | 176 | .bus_id = "w1 bus slave", |
162 | .driver = &w1_slave_driver, | 177 | .driver = &w1_slave_driver, |
178 | .release = &w1_slave_release | ||
163 | }; | 179 | }; |
164 | 180 | ||
165 | static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf) | 181 | static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf) |
@@ -406,8 +422,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
406 | (unsigned int) sl->reg_num.family, | 422 | (unsigned int) sl->reg_num.family, |
407 | (unsigned long long) sl->reg_num.id); | 423 | (unsigned long long) sl->reg_num.id); |
408 | 424 | ||
409 | dev_dbg(&sl->dev, "%s: registering %s.\n", __func__, | 425 | dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__, &sl->dev.bus_id[0]); |
410 | &sl->dev.bus_id[0]); | ||
411 | 426 | ||
412 | err = device_register(&sl->dev); | 427 | err = device_register(&sl->dev); |
413 | if (err < 0) { | 428 | if (err < 0) { |
@@ -480,7 +495,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
480 | 495 | ||
481 | memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); | 496 | memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); |
482 | atomic_set(&sl->refcnt, 0); | 497 | atomic_set(&sl->refcnt, 0); |
483 | init_completion(&sl->dev_released); | 498 | init_completion(&sl->released); |
484 | 499 | ||
485 | spin_lock(&w1_flock); | 500 | spin_lock(&w1_flock); |
486 | f = w1_family_registered(rn->family); | 501 | f = w1_family_registered(rn->family); |
@@ -512,6 +527,8 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
512 | msg.type = W1_SLAVE_ADD; | 527 | msg.type = W1_SLAVE_ADD; |
513 | w1_netlink_send(dev, &msg); | 528 | w1_netlink_send(dev, &msg); |
514 | 529 | ||
530 | dev_info(&dev->dev, "Finished %s for sl=%p.\n", __func__, sl); | ||
531 | |||
515 | return 0; | 532 | return 0; |
516 | } | 533 | } |
517 | 534 | ||
@@ -519,29 +536,23 @@ static void w1_slave_detach(struct w1_slave *sl) | |||
519 | { | 536 | { |
520 | struct w1_netlink_msg msg; | 537 | struct w1_netlink_msg msg; |
521 | 538 | ||
522 | dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name); | 539 | dev_info(&sl->dev, "%s: detaching %s [%p].\n", __func__, sl->name, sl); |
523 | 540 | ||
524 | while (atomic_read(&sl->refcnt)) { | 541 | list_del(&sl->w1_slave_entry); |
525 | printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n", | ||
526 | sl->name, atomic_read(&sl->refcnt)); | ||
527 | |||
528 | if (msleep_interruptible(1000)) | ||
529 | flush_signals(current); | ||
530 | } | ||
531 | 542 | ||
532 | if (sl->family->fops && sl->family->fops->remove_slave) | 543 | if (sl->family->fops && sl->family->fops->remove_slave) |
533 | sl->family->fops->remove_slave(sl); | 544 | sl->family->fops->remove_slave(sl); |
534 | 545 | ||
546 | memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id)); | ||
547 | msg.type = W1_SLAVE_REMOVE; | ||
548 | w1_netlink_send(sl->master, &msg); | ||
549 | |||
535 | sysfs_remove_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id); | 550 | sysfs_remove_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id); |
536 | device_remove_file(&sl->dev, &w1_slave_attr_name); | 551 | device_remove_file(&sl->dev, &w1_slave_attr_name); |
537 | device_unregister(&sl->dev); | 552 | device_unregister(&sl->dev); |
538 | w1_family_put(sl->family); | ||
539 | 553 | ||
540 | sl->master->slave_count--; | 554 | wait_for_completion(&sl->released); |
541 | 555 | kfree(sl); | |
542 | memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id)); | ||
543 | msg.type = W1_SLAVE_REMOVE; | ||
544 | w1_netlink_send(sl->master, &msg); | ||
545 | } | 556 | } |
546 | 557 | ||
547 | static struct w1_master *w1_search_master(unsigned long data) | 558 | static struct w1_master *w1_search_master(unsigned long data) |
@@ -713,7 +724,7 @@ static int w1_control(void *data) | |||
713 | have_to_wait = 0; | 724 | have_to_wait = 0; |
714 | 725 | ||
715 | try_to_freeze(); | 726 | try_to_freeze(); |
716 | msleep_interruptible(w1_timeout * 1000); | 727 | msleep_interruptible(w1_control_timeout * 1000); |
717 | 728 | ||
718 | if (signal_pending(current)) | 729 | if (signal_pending(current)) |
719 | flush_signals(current); | 730 | flush_signals(current); |
@@ -746,13 +757,12 @@ static int w1_control(void *data) | |||
746 | list_del(&dev->w1_master_entry); | 757 | list_del(&dev->w1_master_entry); |
747 | spin_unlock_bh(&w1_mlock); | 758 | spin_unlock_bh(&w1_mlock); |
748 | 759 | ||
760 | down(&dev->mutex); | ||
749 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | 761 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
750 | list_del(&sl->w1_slave_entry); | ||
751 | |||
752 | w1_slave_detach(sl); | 762 | w1_slave_detach(sl); |
753 | kfree(sl); | ||
754 | } | 763 | } |
755 | w1_destroy_master_attributes(dev); | 764 | w1_destroy_master_attributes(dev); |
765 | up(&dev->mutex); | ||
756 | atomic_dec(&dev->refcnt); | 766 | atomic_dec(&dev->refcnt); |
757 | continue; | 767 | continue; |
758 | } | 768 | } |
@@ -760,19 +770,17 @@ static int w1_control(void *data) | |||
760 | if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) { | 770 | if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) { |
761 | dev_info(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name); | 771 | dev_info(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name); |
762 | down(&dev->mutex); | 772 | down(&dev->mutex); |
763 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) { | 773 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
764 | if (sl->family->fid == W1_FAMILY_DEFAULT) { | 774 | if (sl->family->fid == W1_FAMILY_DEFAULT) { |
765 | struct w1_reg_num rn; | 775 | struct w1_reg_num rn; |
766 | list_del(&sl->w1_slave_entry); | ||
767 | w1_slave_detach(sl); | ||
768 | 776 | ||
769 | memcpy(&rn, &sl->reg_num, sizeof(rn)); | 777 | memcpy(&rn, &sl->reg_num, sizeof(rn)); |
770 | 778 | w1_slave_detach(sl); | |
771 | kfree(sl); | ||
772 | 779 | ||
773 | w1_attach_slave_device(dev, &rn); | 780 | w1_attach_slave_device(dev, &rn); |
774 | } | 781 | } |
775 | } | 782 | } |
783 | dev_info(&dev->dev, "Reconnecting slaves in device %s has been finished.\n", dev->name); | ||
776 | clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); | 784 | clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); |
777 | up(&dev->mutex); | 785 | up(&dev->mutex); |
778 | } | 786 | } |
@@ -816,10 +824,7 @@ int w1_process(void *data) | |||
816 | 824 | ||
817 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | 825 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
818 | if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { | 826 | if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { |
819 | list_del (&sl->w1_slave_entry); | ||
820 | |||
821 | w1_slave_detach(sl); | 827 | w1_slave_detach(sl); |
822 | kfree(sl); | ||
823 | 828 | ||
824 | dev->slave_count--; | 829 | dev->slave_count--; |
825 | } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) | 830 | } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) |
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 13edc82bc7de..6cc7f0c5d434 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h | |||
@@ -76,7 +76,7 @@ struct w1_slave | |||
76 | struct w1_master *master; | 76 | struct w1_master *master; |
77 | struct w1_family *family; | 77 | struct w1_family *family; |
78 | struct device dev; | 78 | struct device dev; |
79 | struct completion dev_released; | 79 | struct completion released; |
80 | }; | 80 | }; |
81 | 81 | ||
82 | typedef void (* w1_slave_found_callback)(unsigned long, u64); | 82 | typedef void (* w1_slave_found_callback)(unsigned long, u64); |
@@ -176,7 +176,6 @@ struct w1_master | |||
176 | 176 | ||
177 | struct device_driver *driver; | 177 | struct device_driver *driver; |
178 | struct device dev; | 178 | struct device dev; |
179 | struct completion dev_released; | ||
180 | struct completion dev_exited; | 179 | struct completion dev_exited; |
181 | 180 | ||
182 | struct w1_bus_master *bus_master; | 181 | struct w1_bus_master *bus_master; |
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index c13724fd0971..c3f67eafc7ec 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c | |||
@@ -76,7 +76,6 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
76 | INIT_LIST_HEAD(&dev->slist); | 76 | INIT_LIST_HEAD(&dev->slist); |
77 | init_MUTEX(&dev->mutex); | 77 | init_MUTEX(&dev->mutex); |
78 | 78 | ||
79 | init_completion(&dev->dev_released); | ||
80 | init_completion(&dev->dev_exited); | 79 | init_completion(&dev->dev_exited); |
81 | 80 | ||
82 | memcpy(&dev->dev, device, sizeof(struct device)); | 81 | memcpy(&dev->dev, device, sizeof(struct device)); |
@@ -107,9 +106,6 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
107 | void w1_free_dev(struct w1_master *dev) | 106 | void w1_free_dev(struct w1_master *dev) |
108 | { | 107 | { |
109 | device_unregister(&dev->dev); | 108 | device_unregister(&dev->dev); |
110 | dev_fini_netlink(dev); | ||
111 | memset(dev, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master)); | ||
112 | kfree(dev); | ||
113 | } | 109 | } |
114 | 110 | ||
115 | int w1_add_master_device(struct w1_bus_master *master) | 111 | int w1_add_master_device(struct w1_bus_master *master) |
@@ -184,7 +180,7 @@ void __w1_remove_master_device(struct w1_master *dev) | |||
184 | __func__, dev->kpid); | 180 | __func__, dev->kpid); |
185 | 181 | ||
186 | while (atomic_read(&dev->refcnt)) { | 182 | while (atomic_read(&dev->refcnt)) { |
187 | printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n", | 183 | dev_dbg(&dev->dev, "Waiting for %s to become free: refcnt=%d.\n", |
188 | dev->name, atomic_read(&dev->refcnt)); | 184 | dev->name, atomic_read(&dev->refcnt)); |
189 | 185 | ||
190 | if (msleep_interruptible(1000)) | 186 | if (msleep_interruptible(1000)) |