aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStanislaw Gruszka <stf_xl@wp.pl>2005-11-29 19:16:41 -0500
committerDavid S. Miller <davem@davemloft.net>2005-11-29 19:16:41 -0500
commit64bf69ddff7637b7ed7acf9b2a823cc0ee519439 (patch)
treefb3a746e36bcfa307979bef2a20ce5f1d32ec537
parentaaaaaadbe7a663d110814db50fcbe7d320eb4c32 (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>
-rw-r--r--drivers/atm/atmtcp.c20
-rw-r--r--drivers/usb/atm/usbatm.c4
-rw-r--r--include/linux/atmdev.h14
-rw-r--r--net/atm/common.c30
-rw-r--r--net/atm/common.h2
-rw-r--r--net/atm/resources.c39
6 files changed, 52 insertions, 57 deletions
diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
index 57f1810fdccd..fc518d85543d 100644
--- a/drivers/atm/atmtcp.c
+++ b/drivers/atm/atmtcp.c
@@ -246,10 +246,6 @@ static void atmtcp_c_close(struct atm_vcc *vcc)
246{ 246{
247 struct atm_dev *atmtcp_dev; 247 struct atm_dev *atmtcp_dev;
248 struct atmtcp_dev_data *dev_data; 248 struct atmtcp_dev_data *dev_data;
249 struct sock *s;
250 struct hlist_node *node;
251 struct atm_vcc *walk;
252 int i;
253 249
254 atmtcp_dev = (struct atm_dev *) vcc->dev_data; 250 atmtcp_dev = (struct atm_dev *) vcc->dev_data;
255 dev_data = PRIV(atmtcp_dev); 251 dev_data = PRIV(atmtcp_dev);
@@ -257,20 +253,8 @@ static void atmtcp_c_close(struct atm_vcc *vcc)
257 if (dev_data->persist) return; 253 if (dev_data->persist) return;
258 atmtcp_dev->dev_data = NULL; 254 atmtcp_dev->dev_data = NULL;
259 kfree(dev_data); 255 kfree(dev_data);
260 shutdown_atm_dev(atmtcp_dev); 256 atm_dev_deregister(atmtcp_dev);
261 vcc->dev_data = NULL; 257 vcc->dev_data = NULL;
262 read_lock(&vcc_sklist_lock);
263 for(i = 0; i < VCC_HTABLE_SIZE; ++i) {
264 struct hlist_head *head = &vcc_hash[i];
265
266 sk_for_each(s, node, head) {
267 walk = atm_sk(s);
268 if (walk->dev != atmtcp_dev)
269 continue;
270 wake_up(s->sk_sleep);
271 }
272 }
273 read_unlock(&vcc_sklist_lock);
274 module_put(THIS_MODULE); 258 module_put(THIS_MODULE);
275} 259}
276 260
@@ -450,7 +434,7 @@ static int atmtcp_remove_persistent(int itf)
450 if (PRIV(dev)->vcc) return 0; 434 if (PRIV(dev)->vcc) return 0;
451 kfree(dev_data); 435 kfree(dev_data);
452 atm_dev_put(dev); 436 atm_dev_put(dev);
453 shutdown_atm_dev(dev); 437 atm_dev_deregister(dev);
454 return 0; 438 return 0;
455} 439}
456 440
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index c466739428b2..2e6593e6c1bd 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -879,7 +879,7 @@ static int usbatm_atm_init(struct usbatm_data *instance)
879 879
880 fail: 880 fail:
881 instance->atm_dev = NULL; 881 instance->atm_dev = NULL;
882 shutdown_atm_dev(atm_dev); /* usbatm_atm_dev_close will eventually be called */ 882 atm_dev_deregister(atm_dev); /* usbatm_atm_dev_close will eventually be called */
883 return ret; 883 return ret;
884} 884}
885 885
@@ -1164,7 +1164,7 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
1164 1164
1165 /* ATM finalize */ 1165 /* ATM finalize */
1166 if (instance->atm_dev) 1166 if (instance->atm_dev)
1167 shutdown_atm_dev(instance->atm_dev); 1167 atm_dev_deregister(instance->atm_dev);
1168 1168
1169 usbatm_put_instance(instance); /* taken in usbatm_usb_probe */ 1169 usbatm_put_instance(instance); /* taken in usbatm_usb_probe */
1170} 1170}
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
index 8fadb073c834..b203ea82a0a8 100644
--- a/include/linux/atmdev.h
+++ b/include/linux/atmdev.h
@@ -274,7 +274,7 @@ enum {
274 274
275 275
276enum { 276enum {
277 ATM_DF_CLOSE, /* close device when last VCC is closed */ 277 ATM_DF_REMOVED, /* device was removed from atm_devs list */
278}; 278};
279 279
280 280
@@ -415,7 +415,6 @@ struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
415 int number,unsigned long *flags); /* number == -1: pick first available */ 415 int number,unsigned long *flags); /* number == -1: pick first available */
416struct atm_dev *atm_dev_lookup(int number); 416struct atm_dev *atm_dev_lookup(int number);
417void atm_dev_deregister(struct atm_dev *dev); 417void atm_dev_deregister(struct atm_dev *dev);
418void shutdown_atm_dev(struct atm_dev *dev);
419void vcc_insert_socket(struct sock *sk); 418void vcc_insert_socket(struct sock *sk);
420 419
421 420
@@ -457,11 +456,12 @@ static inline void atm_dev_hold(struct atm_dev *dev)
457 456
458static inline void atm_dev_put(struct atm_dev *dev) 457static inline void atm_dev_put(struct atm_dev *dev)
459{ 458{
460 atomic_dec(&dev->refcnt); 459 if (atomic_dec_and_test(&dev->refcnt)) {
461 460 BUG_ON(!test_bit(ATM_DF_REMOVED, &dev->flags));
462 if ((atomic_read(&dev->refcnt) == 1) && 461 if (dev->ops->dev_close)
463 test_bit(ATM_DF_CLOSE,&dev->flags)) 462 dev->ops->dev_close(dev);
464 shutdown_atm_dev(dev); 463 kfree(dev);
464 }
465} 465}
466 466
467 467
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)
221EXPORT_SYMBOL(vcc_release_async); 221EXPORT_SYMBOL(vcc_release_async);
222 222
223 223
224void 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
224static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) 247static 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 */
48int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos); 48int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos);
49 49
50void 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
73struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, 74struct 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
124void atm_dev_deregister(struct atm_dev *dev) 125void 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
148void 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)
433EXPORT_SYMBOL(atm_dev_register); 419EXPORT_SYMBOL(atm_dev_register);
434EXPORT_SYMBOL(atm_dev_deregister); 420EXPORT_SYMBOL(atm_dev_deregister);
435EXPORT_SYMBOL(atm_dev_lookup); 421EXPORT_SYMBOL(atm_dev_lookup);
436EXPORT_SYMBOL(shutdown_atm_dev);