diff options
author | Stanislaw Gruszka <stf_xl@wp.pl> | 2005-11-29 19:16:41 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-11-29 19:16:41 -0500 |
commit | 64bf69ddff7637b7ed7acf9b2a823cc0ee519439 (patch) | |
tree | fb3a746e36bcfa307979bef2a20ce5f1d32ec537 /net/atm | |
parent | aaaaaadbe7a663d110814db50fcbe7d320eb4c32 (diff) |
[ATM]: deregistration removes device from atm_devs list immediately
atm_dev_deregister() removes device from atm_dev list immediately to
prevent operations on a phantom device. Decision to free device based
only on ->refcnt now. Remove shutdown_atm_dev() use atm_dev_deregister()
instead. atm_dev_deregister() also asynchronously releases all vccs
related to device.
Signed-off-by: Stanislaw Gruszka <stf_xl@wp.pl>
Signed-off-by: Chas Williams <chas@cmf.nrl.navy.mil>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/atm')
-rw-r--r-- | net/atm/common.c | 30 | ||||
-rw-r--r-- | net/atm/common.h | 2 | ||||
-rw-r--r-- | net/atm/resources.c | 39 |
3 files changed, 41 insertions, 30 deletions
diff --git a/net/atm/common.c b/net/atm/common.c index 9e016f404e14..6656b111cc05 100644 --- a/net/atm/common.c +++ b/net/atm/common.c | |||
@@ -221,6 +221,29 @@ void vcc_release_async(struct atm_vcc *vcc, int reply) | |||
221 | EXPORT_SYMBOL(vcc_release_async); | 221 | EXPORT_SYMBOL(vcc_release_async); |
222 | 222 | ||
223 | 223 | ||
224 | void atm_dev_release_vccs(struct atm_dev *dev) | ||
225 | { | ||
226 | int i; | ||
227 | |||
228 | write_lock_irq(&vcc_sklist_lock); | ||
229 | for (i = 0; i < VCC_HTABLE_SIZE; i++) { | ||
230 | struct hlist_head *head = &vcc_hash[i]; | ||
231 | struct hlist_node *node, *tmp; | ||
232 | struct sock *s; | ||
233 | struct atm_vcc *vcc; | ||
234 | |||
235 | sk_for_each_safe(s, node, tmp, head) { | ||
236 | vcc = atm_sk(s); | ||
237 | if (vcc->dev == dev) { | ||
238 | vcc_release_async(vcc, -EPIPE); | ||
239 | sk_del_node_init(s); | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | write_unlock_irq(&vcc_sklist_lock); | ||
244 | } | ||
245 | |||
246 | |||
224 | static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) | 247 | static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) |
225 | { | 248 | { |
226 | int max_sdu; | 249 | int max_sdu; |
@@ -332,12 +355,13 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi, | |||
332 | return -EINVAL; | 355 | return -EINVAL; |
333 | if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE)) | 356 | if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE)) |
334 | return -EPERM; | 357 | return -EPERM; |
335 | error = 0; | 358 | error = -ENODEV; |
336 | if (!try_module_get(dev->ops->owner)) | 359 | if (!try_module_get(dev->ops->owner)) |
337 | return -ENODEV; | 360 | return error; |
338 | vcc->dev = dev; | 361 | vcc->dev = dev; |
339 | write_lock_irq(&vcc_sklist_lock); | 362 | write_lock_irq(&vcc_sklist_lock); |
340 | if ((error = find_ci(vcc, &vpi, &vci))) { | 363 | if (test_bit(ATM_DF_REMOVED, &dev->flags) || |
364 | (error = find_ci(vcc, &vpi, &vci))) { | ||
341 | write_unlock_irq(&vcc_sklist_lock); | 365 | write_unlock_irq(&vcc_sklist_lock); |
342 | goto fail_module_put; | 366 | goto fail_module_put; |
343 | } | 367 | } |
diff --git a/net/atm/common.h b/net/atm/common.h index e49ed41c0e33..4887c317cefe 100644 --- a/net/atm/common.h +++ b/net/atm/common.h | |||
@@ -47,4 +47,6 @@ static inline void atm_proc_exit(void) | |||
47 | /* SVC */ | 47 | /* SVC */ |
48 | int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos); | 48 | int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos); |
49 | 49 | ||
50 | void atm_dev_release_vccs(struct atm_dev *dev); | ||
51 | |||
50 | #endif | 52 | #endif |
diff --git a/net/atm/resources.c b/net/atm/resources.c index ad533b02b84f..c8c459fcb038 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c | |||
@@ -70,6 +70,7 @@ struct atm_dev *atm_dev_lookup(int number) | |||
70 | return dev; | 70 | return dev; |
71 | } | 71 | } |
72 | 72 | ||
73 | |||
73 | struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, | 74 | struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, |
74 | int number, unsigned long *flags) | 75 | int number, unsigned long *flags) |
75 | { | 76 | { |
@@ -123,37 +124,22 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, | |||
123 | 124 | ||
124 | void atm_dev_deregister(struct atm_dev *dev) | 125 | void atm_dev_deregister(struct atm_dev *dev) |
125 | { | 126 | { |
126 | unsigned long warning_time; | 127 | BUG_ON(test_bit(ATM_DF_REMOVED, &dev->flags)); |
127 | 128 | set_bit(ATM_DF_REMOVED, &dev->flags); | |
128 | atm_proc_dev_deregister(dev); | 129 | |
129 | 130 | /* | |
131 | * if we remove current device from atm_devs list, new device | ||
132 | * with same number can appear, such we need deregister proc, | ||
133 | * release async all vccs and remove them from vccs list too | ||
134 | */ | ||
130 | down(&atm_dev_mutex); | 135 | down(&atm_dev_mutex); |
131 | list_del(&dev->dev_list); | 136 | list_del(&dev->dev_list); |
132 | up(&atm_dev_mutex); | 137 | up(&atm_dev_mutex); |
133 | 138 | ||
134 | warning_time = jiffies; | 139 | atm_dev_release_vccs(dev); |
135 | while (atomic_read(&dev->refcnt) != 1) { | 140 | atm_proc_dev_deregister(dev); |
136 | msleep(250); | ||
137 | if ((jiffies - warning_time) > 10 * HZ) { | ||
138 | printk(KERN_EMERG "atm_dev_deregister: waiting for " | ||
139 | "dev %d to become free. Usage count = %d\n", | ||
140 | dev->number, atomic_read(&dev->refcnt)); | ||
141 | warning_time = jiffies; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | kfree(dev); | ||
146 | } | ||
147 | 141 | ||
148 | void shutdown_atm_dev(struct atm_dev *dev) | 142 | atm_dev_put(dev); |
149 | { | ||
150 | if (atomic_read(&dev->refcnt) > 1) { | ||
151 | set_bit(ATM_DF_CLOSE, &dev->flags); | ||
152 | return; | ||
153 | } | ||
154 | if (dev->ops->dev_close) | ||
155 | dev->ops->dev_close(dev); | ||
156 | atm_dev_deregister(dev); | ||
157 | } | 143 | } |
158 | 144 | ||
159 | 145 | ||
@@ -433,4 +419,3 @@ void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
433 | EXPORT_SYMBOL(atm_dev_register); | 419 | EXPORT_SYMBOL(atm_dev_register); |
434 | EXPORT_SYMBOL(atm_dev_deregister); | 420 | EXPORT_SYMBOL(atm_dev_deregister); |
435 | EXPORT_SYMBOL(atm_dev_lookup); | 421 | EXPORT_SYMBOL(atm_dev_lookup); |
436 | EXPORT_SYMBOL(shutdown_atm_dev); | ||