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 223c7ad5bd0..02cc7e71efe 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, */ -int atm_pcr_goal(struct atm_trafprm *tp) +int atm_pcr_goal(const struct atm_trafprm *tp) { - if (tp->pcr && tp->pcr != ATM_MAX_PCR) return -tp->pcr; - if (tp->min_pcr && !tp->pcr) return tp->min_pcr; - if (tp->max_pcr != ATM_MAX_PCR) return -tp->max_pcr; + if (tp->pcr && tp->pcr != ATM_MAX_PCR) + return -tp->pcr; + if (tp->min_pcr && !tp->pcr) + return tp->min_pcr; + if (tp->max_pcr != ATM_MAX_PCR) + return -tp->max_pcr; return 0; } diff --git a/net/atm/common.c b/net/atm/common.c index 63feea49fb1..6656b111cc0 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) EXPORT_SYMBOL(vcc_release_async); +void atm_dev_release_vccs(struct atm_dev *dev) +{ + int i; + + write_lock_irq(&vcc_sklist_lock); + for (i = 0; i < VCC_HTABLE_SIZE; i++) { + struct hlist_head *head = &vcc_hash[i]; + struct hlist_node *node, *tmp; + struct sock *s; + struct atm_vcc *vcc; + + sk_for_each_safe(s, node, tmp, head) { + vcc = atm_sk(s); + if (vcc->dev == dev) { + vcc_release_async(vcc, -EPIPE); + sk_del_node_init(s); + } + } + } + write_unlock_irq(&vcc_sklist_lock); +} + + static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) { int max_sdu; @@ -332,12 +355,13 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi, return -EINVAL; if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE)) return -EPERM; - error = 0; + error = -ENODEV; if (!try_module_get(dev->ops->owner)) - return -ENODEV; + return error; vcc->dev = dev; write_lock_irq(&vcc_sklist_lock); - if ((error = find_ci(vcc, &vpi, &vci))) { + if (test_bit(ATM_DF_REMOVED, &dev->flags) || + (error = find_ci(vcc, &vpi, &vci))) { write_unlock_irq(&vcc_sklist_lock); goto fail_module_put; } @@ -423,33 +447,23 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci) if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) return -EINVAL; - if (itf != ATM_ITF_ANY) { - dev = atm_dev_lookup(itf); - if (!dev) - return -ENODEV; - error = __vcc_connect(vcc, dev, vpi, vci); - if (error) { - atm_dev_put(dev); - return error; - } + if (likely(itf != ATM_ITF_ANY)) { + dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf); } else { - struct list_head *p, *next; - dev = NULL; - spin_lock(&atm_dev_lock); - list_for_each_safe(p, next, &atm_devs) { - dev = list_entry(p, struct atm_dev, dev_list); + down(&atm_dev_mutex); + if (!list_empty(&atm_devs)) { + dev = list_entry(atm_devs.next, struct atm_dev, dev_list); atm_dev_hold(dev); - spin_unlock(&atm_dev_lock); - if (!__vcc_connect(vcc, dev, vpi, vci)) - break; - atm_dev_put(dev); - dev = NULL; - spin_lock(&atm_dev_lock); } - spin_unlock(&atm_dev_lock); - if (!dev) - return -ENODEV; + up(&atm_dev_mutex); + } + if (!dev) + return -ENODEV; + error = __vcc_connect(vcc, dev, vpi, vci); + if (error) { + atm_dev_put(dev); + return error; } if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) set_bit(ATM_VF_PARTIAL,&vcc->flags); diff --git a/net/atm/common.h b/net/atm/common.h index e49ed41c0e3..4887c317cef 100644 --- a/net/atm/common.h +++ b/net/atm/common.h @@ -47,4 +47,6 @@ static inline void atm_proc_exit(void) /* SVC */ int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos); +void atm_dev_release_vccs(struct atm_dev *dev); + #endif diff --git a/net/atm/resources.c b/net/atm/resources.c index 415d2615d47..c8c459fcb03 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -25,7 +25,7 @@ LIST_HEAD(atm_devs); -DEFINE_SPINLOCK(atm_dev_lock); +DECLARE_MUTEX(atm_dev_mutex); static struct atm_dev *__alloc_atm_dev(const char *type) { @@ -52,7 +52,7 @@ static struct atm_dev *__atm_dev_lookup(int number) list_for_each(p, &atm_devs) { dev = list_entry(p, struct atm_dev, dev_list); - if ((dev->ops) && (dev->number == number)) { + if (dev->number == number) { atm_dev_hold(dev); return dev; } @@ -64,12 +64,13 @@ struct atm_dev *atm_dev_lookup(int number) { struct atm_dev *dev; - spin_lock(&atm_dev_lock); + down(&atm_dev_mutex); dev = __atm_dev_lookup(number); - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); return dev; } + struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, int number, unsigned long *flags) { @@ -81,11 +82,11 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, type); return NULL; } - spin_lock(&atm_dev_lock); + down(&atm_dev_mutex); if (number != -1) { if ((inuse = __atm_dev_lookup(number))) { atm_dev_put(inuse); - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); kfree(dev); return NULL; } @@ -105,19 +106,17 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, memset(&dev->flags, 0, sizeof(dev->flags)); memset(&dev->stats, 0, sizeof(dev->stats)); atomic_set(&dev->refcnt, 1); - list_add_tail(&dev->dev_list, &atm_devs); - spin_unlock(&atm_dev_lock); if (atm_proc_dev_register(dev) < 0) { printk(KERN_ERR "atm_dev_register: " "atm_proc_dev_register failed for dev %s\n", type); - spin_lock(&atm_dev_lock); - list_del(&dev->dev_list); - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); kfree(dev); return NULL; } + list_add_tail(&dev->dev_list, &atm_devs); + up(&atm_dev_mutex); return dev; } @@ -125,37 +124,22 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, void atm_dev_deregister(struct atm_dev *dev) { - unsigned long warning_time; + BUG_ON(test_bit(ATM_DF_REMOVED, &dev->flags)); + set_bit(ATM_DF_REMOVED, &dev->flags); + + /* + * if we remove current device from atm_devs list, new device + * with same number can appear, such we need deregister proc, + * release async all vccs and remove them from vccs list too + */ + down(&atm_dev_mutex); + list_del(&dev->dev_list); + up(&atm_dev_mutex); + atm_dev_release_vccs(dev); atm_proc_dev_deregister(dev); - spin_lock(&atm_dev_lock); - list_del(&dev->dev_list); - spin_unlock(&atm_dev_lock); - - warning_time = jiffies; - while (atomic_read(&dev->refcnt) != 1) { - msleep(250); - if ((jiffies - warning_time) > 10 * HZ) { - printk(KERN_EMERG "atm_dev_deregister: waiting for " - "dev %d to become free. Usage count = %d\n", - dev->number, atomic_read(&dev->refcnt)); - warning_time = jiffies; - } - } - - kfree(dev); -} - -void shutdown_atm_dev(struct atm_dev *dev) -{ - if (atomic_read(&dev->refcnt) > 1) { - set_bit(ATM_DF_CLOSE, &dev->flags); - return; - } - if (dev->ops->dev_close) - dev->ops->dev_close(dev); - atm_dev_deregister(dev); + atm_dev_put(dev); } @@ -211,16 +195,16 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) return -EFAULT; if (get_user(len, &iobuf->length)) return -EFAULT; - spin_lock(&atm_dev_lock); + down(&atm_dev_mutex); list_for_each(p, &atm_devs) size += sizeof(int); if (size > len) { - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); return -E2BIG; } tmp_buf = kmalloc(size, GFP_ATOMIC); if (!tmp_buf) { - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); return -ENOMEM; } tmp_p = tmp_buf; @@ -228,7 +212,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) dev = list_entry(p, struct atm_dev, dev_list); *tmp_p++ = dev->number; } - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); error = ((copy_to_user(buf, tmp_buf, size)) || put_user(size, &iobuf->length)) ? -EFAULT : 0; @@ -245,7 +229,8 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) if (get_user(number, &sioc->number)) return -EFAULT; - if (!(dev = atm_dev_lookup(number))) + if (!(dev = try_then_request_module(atm_dev_lookup(number), + "atm-device-%d", number))) return -ENODEV; switch (cmd) { @@ -414,13 +399,13 @@ static __inline__ void *dev_get_idx(loff_t left) void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) { - spin_lock(&atm_dev_lock); + down(&atm_dev_mutex); return *pos ? dev_get_idx(*pos) : (void *) 1; } void atm_dev_seq_stop(struct seq_file *seq, void *v) { - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); } 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) EXPORT_SYMBOL(atm_dev_register); EXPORT_SYMBOL(atm_dev_deregister); EXPORT_SYMBOL(atm_dev_lookup); -EXPORT_SYMBOL(shutdown_atm_dev); diff --git a/net/atm/resources.h b/net/atm/resources.h index 12910619dbb..b7fb82a93b4 100644 --- a/net/atm/resources.h +++ b/net/atm/resources.h @@ -11,8 +11,7 @@ extern struct list_head atm_devs; -extern spinlock_t atm_dev_lock; - +extern struct semaphore atm_dev_mutex; int atm_dev_ioctl(unsigned int cmd, void __user *arg); |