diff options
Diffstat (limited to 'net/atm')
-rw-r--r-- | net/atm/atm_misc.c | 11 | ||||
-rw-r--r-- | net/atm/common.c | 66 | ||||
-rw-r--r-- | net/atm/common.h | 2 | ||||
-rw-r--r-- | net/atm/resources.c | 78 | ||||
-rw-r--r-- | net/atm/resources.h | 3 |
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 | ||
77 | int atm_pcr_goal(struct atm_trafprm *tp) | 77 | int 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) | |||
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 | } |
@@ -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 */ |
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 415d2615d4..c8c459fcb0 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c | |||
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | 26 | ||
27 | LIST_HEAD(atm_devs); | 27 | LIST_HEAD(atm_devs); |
28 | DEFINE_SPINLOCK(atm_dev_lock); | 28 | DECLARE_MUTEX(atm_dev_mutex); |
29 | 29 | ||
30 | static struct atm_dev *__alloc_atm_dev(const char *type) | 30 | static 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 | |||
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 | { |
@@ -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 | ||
126 | void atm_dev_deregister(struct atm_dev *dev) | 125 | void 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 | |||
150 | void 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 | ||
415 | void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) | 400 | void *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 | ||
421 | void atm_dev_seq_stop(struct seq_file *seq, void *v) | 406 | void 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 | ||
426 | void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 411 | void *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) | |||
434 | EXPORT_SYMBOL(atm_dev_register); | 419 | EXPORT_SYMBOL(atm_dev_register); |
435 | EXPORT_SYMBOL(atm_dev_deregister); | 420 | EXPORT_SYMBOL(atm_dev_deregister); |
436 | EXPORT_SYMBOL(atm_dev_lookup); | 421 | EXPORT_SYMBOL(atm_dev_lookup); |
437 | EXPORT_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 | ||
13 | extern struct list_head atm_devs; | 13 | extern struct list_head atm_devs; |
14 | extern spinlock_t atm_dev_lock; | 14 | extern struct semaphore atm_dev_mutex; |
15 | |||
16 | 15 | ||
17 | int atm_dev_ioctl(unsigned int cmd, void __user *arg); | 16 | int atm_dev_ioctl(unsigned int cmd, void __user *arg); |
18 | 17 | ||