aboutsummaryrefslogtreecommitdiffstats
path: root/net/atm
diff options
context:
space:
mode:
Diffstat (limited to 'net/atm')
-rw-r--r--net/atm/atm_misc.c11
-rw-r--r--net/atm/common.c66
-rw-r--r--net/atm/common.h2
-rw-r--r--net/atm/resources.c78
-rw-r--r--net/atm/resources.h3
5 files changed, 81 insertions, 79 deletions
diff --git a/net/atm/atm_misc.c b/net/atm/atm_misc.c
index 223c7ad5bd..02cc7e71ef 100644
--- a/net/atm/atm_misc.c
+++ b/net/atm/atm_misc.c
@@ -74,11 +74,14 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
74 */ 74 */
75 75
76 76
77int atm_pcr_goal(struct atm_trafprm *tp) 77int atm_pcr_goal(const struct atm_trafprm *tp)
78{ 78{
79 if (tp->pcr && tp->pcr != ATM_MAX_PCR) return -tp->pcr; 79 if (tp->pcr && tp->pcr != ATM_MAX_PCR)
80 if (tp->min_pcr && !tp->pcr) return tp->min_pcr; 80 return -tp->pcr;
81 if (tp->max_pcr != ATM_MAX_PCR) return -tp->max_pcr; 81 if (tp->min_pcr && !tp->pcr)
82 return tp->min_pcr;
83 if (tp->max_pcr != ATM_MAX_PCR)
84 return -tp->max_pcr;
82 return 0; 85 return 0;
83} 86}
84 87
diff --git a/net/atm/common.c b/net/atm/common.c
index 63feea49fb..6656b111cc 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 }
@@ -423,33 +447,23 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
423 if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || 447 if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
424 vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) 448 vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
425 return -EINVAL; 449 return -EINVAL;
426 if (itf != ATM_ITF_ANY) { 450 if (likely(itf != ATM_ITF_ANY)) {
427 dev = atm_dev_lookup(itf); 451 dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf);
428 if (!dev)
429 return -ENODEV;
430 error = __vcc_connect(vcc, dev, vpi, vci);
431 if (error) {
432 atm_dev_put(dev);
433 return error;
434 }
435 } else { 452 } else {
436 struct list_head *p, *next;
437
438 dev = NULL; 453 dev = NULL;
439 spin_lock(&atm_dev_lock); 454 down(&atm_dev_mutex);
440 list_for_each_safe(p, next, &atm_devs) { 455 if (!list_empty(&atm_devs)) {
441 dev = list_entry(p, struct atm_dev, dev_list); 456 dev = list_entry(atm_devs.next, struct atm_dev, dev_list);
442 atm_dev_hold(dev); 457 atm_dev_hold(dev);
443 spin_unlock(&atm_dev_lock);
444 if (!__vcc_connect(vcc, dev, vpi, vci))
445 break;
446 atm_dev_put(dev);
447 dev = NULL;
448 spin_lock(&atm_dev_lock);
449 } 458 }
450 spin_unlock(&atm_dev_lock); 459 up(&atm_dev_mutex);
451 if (!dev) 460 }
452 return -ENODEV; 461 if (!dev)
462 return -ENODEV;
463 error = __vcc_connect(vcc, dev, vpi, vci);
464 if (error) {
465 atm_dev_put(dev);
466 return error;
453 } 467 }
454 if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) 468 if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
455 set_bit(ATM_VF_PARTIAL,&vcc->flags); 469 set_bit(ATM_VF_PARTIAL,&vcc->flags);
diff --git a/net/atm/common.h b/net/atm/common.h
index e49ed41c0e..4887c317ce 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 415d2615d4..c8c459fcb0 100644
--- a/net/atm/resources.c
+++ b/net/atm/resources.c
@@ -25,7 +25,7 @@
25 25
26 26
27LIST_HEAD(atm_devs); 27LIST_HEAD(atm_devs);
28DEFINE_SPINLOCK(atm_dev_lock); 28DECLARE_MUTEX(atm_dev_mutex);
29 29
30static struct atm_dev *__alloc_atm_dev(const char *type) 30static struct atm_dev *__alloc_atm_dev(const char *type)
31{ 31{
@@ -52,7 +52,7 @@ static struct atm_dev *__atm_dev_lookup(int number)
52 52
53 list_for_each(p, &atm_devs) { 53 list_for_each(p, &atm_devs) {
54 dev = list_entry(p, struct atm_dev, dev_list); 54 dev = list_entry(p, struct atm_dev, dev_list);
55 if ((dev->ops) && (dev->number == number)) { 55 if (dev->number == number) {
56 atm_dev_hold(dev); 56 atm_dev_hold(dev);
57 return dev; 57 return dev;
58 } 58 }
@@ -64,12 +64,13 @@ struct atm_dev *atm_dev_lookup(int number)
64{ 64{
65 struct atm_dev *dev; 65 struct atm_dev *dev;
66 66
67 spin_lock(&atm_dev_lock); 67 down(&atm_dev_mutex);
68 dev = __atm_dev_lookup(number); 68 dev = __atm_dev_lookup(number);
69 spin_unlock(&atm_dev_lock); 69 up(&atm_dev_mutex);
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{
@@ -81,11 +82,11 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
81 type); 82 type);
82 return NULL; 83 return NULL;
83 } 84 }
84 spin_lock(&atm_dev_lock); 85 down(&atm_dev_mutex);
85 if (number != -1) { 86 if (number != -1) {
86 if ((inuse = __atm_dev_lookup(number))) { 87 if ((inuse = __atm_dev_lookup(number))) {
87 atm_dev_put(inuse); 88 atm_dev_put(inuse);
88 spin_unlock(&atm_dev_lock); 89 up(&atm_dev_mutex);
89 kfree(dev); 90 kfree(dev);
90 return NULL; 91 return NULL;
91 } 92 }
@@ -105,19 +106,17 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
105 memset(&dev->flags, 0, sizeof(dev->flags)); 106 memset(&dev->flags, 0, sizeof(dev->flags));
106 memset(&dev->stats, 0, sizeof(dev->stats)); 107 memset(&dev->stats, 0, sizeof(dev->stats));
107 atomic_set(&dev->refcnt, 1); 108 atomic_set(&dev->refcnt, 1);
108 list_add_tail(&dev->dev_list, &atm_devs);
109 spin_unlock(&atm_dev_lock);
110 109
111 if (atm_proc_dev_register(dev) < 0) { 110 if (atm_proc_dev_register(dev) < 0) {
112 printk(KERN_ERR "atm_dev_register: " 111 printk(KERN_ERR "atm_dev_register: "
113 "atm_proc_dev_register failed for dev %s\n", 112 "atm_proc_dev_register failed for dev %s\n",
114 type); 113 type);
115 spin_lock(&atm_dev_lock); 114 up(&atm_dev_mutex);
116 list_del(&dev->dev_list);
117 spin_unlock(&atm_dev_lock);
118 kfree(dev); 115 kfree(dev);
119 return NULL; 116 return NULL;
120 } 117 }
118 list_add_tail(&dev->dev_list, &atm_devs);
119 up(&atm_dev_mutex);
121 120
122 return dev; 121 return dev;
123} 122}
@@ -125,37 +124,22 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
125 124
126void atm_dev_deregister(struct atm_dev *dev) 125void atm_dev_deregister(struct atm_dev *dev)
127{ 126{
128 unsigned long warning_time; 127 BUG_ON(test_bit(ATM_DF_REMOVED, &dev->flags));
128 set_bit(ATM_DF_REMOVED, &dev->flags);
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 */
135 down(&atm_dev_mutex);
136 list_del(&dev->dev_list);
137 up(&atm_dev_mutex);
129 138
139 atm_dev_release_vccs(dev);
130 atm_proc_dev_deregister(dev); 140 atm_proc_dev_deregister(dev);
131 141
132 spin_lock(&atm_dev_lock); 142 atm_dev_put(dev);
133 list_del(&dev->dev_list);
134 spin_unlock(&atm_dev_lock);
135
136 warning_time = jiffies;
137 while (atomic_read(&dev->refcnt) != 1) {
138 msleep(250);
139 if ((jiffies - warning_time) > 10 * HZ) {
140 printk(KERN_EMERG "atm_dev_deregister: waiting for "
141 "dev %d to become free. Usage count = %d\n",
142 dev->number, atomic_read(&dev->refcnt));
143 warning_time = jiffies;
144 }
145 }
146
147 kfree(dev);
148}
149
150void shutdown_atm_dev(struct atm_dev *dev)
151{
152 if (atomic_read(&dev->refcnt) > 1) {
153 set_bit(ATM_DF_CLOSE, &dev->flags);
154 return;
155 }
156 if (dev->ops->dev_close)
157 dev->ops->dev_close(dev);
158 atm_dev_deregister(dev);
159} 143}
160 144
161 145
@@ -211,16 +195,16 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg)
211 return -EFAULT; 195 return -EFAULT;
212 if (get_user(len, &iobuf->length)) 196 if (get_user(len, &iobuf->length))
213 return -EFAULT; 197 return -EFAULT;
214 spin_lock(&atm_dev_lock); 198 down(&atm_dev_mutex);
215 list_for_each(p, &atm_devs) 199 list_for_each(p, &atm_devs)
216 size += sizeof(int); 200 size += sizeof(int);
217 if (size > len) { 201 if (size > len) {
218 spin_unlock(&atm_dev_lock); 202 up(&atm_dev_mutex);
219 return -E2BIG; 203 return -E2BIG;
220 } 204 }
221 tmp_buf = kmalloc(size, GFP_ATOMIC); 205 tmp_buf = kmalloc(size, GFP_ATOMIC);
222 if (!tmp_buf) { 206 if (!tmp_buf) {
223 spin_unlock(&atm_dev_lock); 207 up(&atm_dev_mutex);
224 return -ENOMEM; 208 return -ENOMEM;
225 } 209 }
226 tmp_p = tmp_buf; 210 tmp_p = tmp_buf;
@@ -228,7 +212,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg)
228 dev = list_entry(p, struct atm_dev, dev_list); 212 dev = list_entry(p, struct atm_dev, dev_list);
229 *tmp_p++ = dev->number; 213 *tmp_p++ = dev->number;
230 } 214 }
231 spin_unlock(&atm_dev_lock); 215 up(&atm_dev_mutex);
232 error = ((copy_to_user(buf, tmp_buf, size)) || 216 error = ((copy_to_user(buf, tmp_buf, size)) ||
233 put_user(size, &iobuf->length)) 217 put_user(size, &iobuf->length))
234 ? -EFAULT : 0; 218 ? -EFAULT : 0;
@@ -245,7 +229,8 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg)
245 if (get_user(number, &sioc->number)) 229 if (get_user(number, &sioc->number))
246 return -EFAULT; 230 return -EFAULT;
247 231
248 if (!(dev = atm_dev_lookup(number))) 232 if (!(dev = try_then_request_module(atm_dev_lookup(number),
233 "atm-device-%d", number)))
249 return -ENODEV; 234 return -ENODEV;
250 235
251 switch (cmd) { 236 switch (cmd) {
@@ -414,13 +399,13 @@ static __inline__ void *dev_get_idx(loff_t left)
414 399
415void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) 400void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos)
416{ 401{
417 spin_lock(&atm_dev_lock); 402 down(&atm_dev_mutex);
418 return *pos ? dev_get_idx(*pos) : (void *) 1; 403 return *pos ? dev_get_idx(*pos) : (void *) 1;
419} 404}
420 405
421void atm_dev_seq_stop(struct seq_file *seq, void *v) 406void atm_dev_seq_stop(struct seq_file *seq, void *v)
422{ 407{
423 spin_unlock(&atm_dev_lock); 408 up(&atm_dev_mutex);
424} 409}
425 410
426void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) 411void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
@@ -434,4 +419,3 @@ void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
434EXPORT_SYMBOL(atm_dev_register); 419EXPORT_SYMBOL(atm_dev_register);
435EXPORT_SYMBOL(atm_dev_deregister); 420EXPORT_SYMBOL(atm_dev_deregister);
436EXPORT_SYMBOL(atm_dev_lookup); 421EXPORT_SYMBOL(atm_dev_lookup);
437EXPORT_SYMBOL(shutdown_atm_dev);
diff --git a/net/atm/resources.h b/net/atm/resources.h
index 12910619db..b7fb82a93b 100644
--- a/net/atm/resources.h
+++ b/net/atm/resources.h
@@ -11,8 +11,7 @@
11 11
12 12
13extern struct list_head atm_devs; 13extern struct list_head atm_devs;
14extern spinlock_t atm_dev_lock; 14extern struct semaphore atm_dev_mutex;
15
16 15
17int atm_dev_ioctl(unsigned int cmd, void __user *arg); 16int atm_dev_ioctl(unsigned int cmd, void __user *arg);
18 17