please apply to 2.6 -- thanks!

[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 <[EMAIL PROTECTED]>
Signed-off-by: Chas Williams <[EMAIL PROTECTED]>

---
commit 66f9fb08f7ee005751eaec22e82e6d314f340036
tree c7e15743a39a77892e9df753be58fb5dbc64b1f1
parent e1a493214355e544068560be5a2aaa144193bd3f
author chas williams <[EMAIL PROTECTED](none)> Tue, 29 Nov 2005 12:37:25 -0500
committer chas williams <[EMAIL PROTECTED](none)> Tue, 29 Nov 2005 12:37:25 
-0500

 drivers/atm/atmtcp.c     |   20 ++------------------
 drivers/usb/atm/usbatm.c |    4 ++--
 include/linux/atmdev.h   |   14 +++++++-------
 net/atm/common.c         |   30 +++++++++++++++++++++++++++---
 net/atm/common.h         |    2 ++
 net/atm/resources.c      |   37 +++++++++++--------------------------
 6 files changed, 51 insertions(+), 56 deletions(-)

diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
--- a/drivers/atm/atmtcp.c
+++ b/drivers/atm/atmtcp.c
@@ -246,10 +246,6 @@ static void atmtcp_c_close(struct atm_vc
 {
        struct atm_dev *atmtcp_dev;
        struct atmtcp_dev_data *dev_data;
-       struct sock *s;
-       struct hlist_node *node;
-       struct atm_vcc *walk;
-       int i;
 
        atmtcp_dev = (struct atm_dev *) vcc->dev_data;
        dev_data = PRIV(atmtcp_dev);
@@ -257,20 +253,8 @@ static void atmtcp_c_close(struct atm_vc
        if (dev_data->persist) return;
        atmtcp_dev->dev_data = NULL;
        kfree(dev_data);
-       shutdown_atm_dev(atmtcp_dev);
+       atm_dev_deregister(atmtcp_dev);
        vcc->dev_data = NULL;
-       read_lock(&vcc_sklist_lock);
-       for(i = 0; i < VCC_HTABLE_SIZE; ++i) {
-               struct hlist_head *head = &vcc_hash[i];
-
-               sk_for_each(s, node, head) {
-                       walk = atm_sk(s);
-                       if (walk->dev != atmtcp_dev)
-                               continue;
-                       wake_up(s->sk_sleep);
-               }
-       }
-       read_unlock(&vcc_sklist_lock);
        module_put(THIS_MODULE);
 }
 
@@ -450,7 +434,7 @@ static int atmtcp_remove_persistent(int 
        if (PRIV(dev)->vcc) return 0;
        kfree(dev_data);
        atm_dev_put(dev);
-       shutdown_atm_dev(dev);
+       atm_dev_deregister(dev);
        return 0;
 }
 
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -879,7 +879,7 @@ static int usbatm_atm_init(struct usbatm
 
  fail:
        instance->atm_dev = NULL;
-       shutdown_atm_dev(atm_dev); /* usbatm_atm_dev_close will eventually be 
called */
+       atm_dev_deregister(atm_dev); /* usbatm_atm_dev_close will eventually be 
called */
        return ret;
 }
 
@@ -1164,7 +1164,7 @@ void usbatm_usb_disconnect(struct usb_in
 
        /* ATM finalize */
        if (instance->atm_dev)
-               shutdown_atm_dev(instance->atm_dev);
+               atm_dev_deregister(instance->atm_dev);
 
        usbatm_put_instance(instance);  /* taken in usbatm_usb_probe */
 }
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
--- a/include/linux/atmdev.h
+++ b/include/linux/atmdev.h
@@ -274,7 +274,7 @@ enum {
 
 
 enum {
-       ATM_DF_CLOSE,           /* close device when last VCC is closed */
+       ATM_DF_REMOVED,         /* device was removed from atm_devs list */
 };
 
 
@@ -415,7 +415,6 @@ struct atm_dev *atm_dev_register(const c
     int number,unsigned long *flags); /* number == -1: pick first available */
 struct atm_dev *atm_dev_lookup(int number);
 void atm_dev_deregister(struct atm_dev *dev);
-void shutdown_atm_dev(struct atm_dev *dev);
 void vcc_insert_socket(struct sock *sk);
 
 
@@ -457,11 +456,12 @@ static inline void atm_dev_hold(struct a
 
 static inline void atm_dev_put(struct atm_dev *dev)
 {
-       atomic_dec(&dev->refcnt);
-
-       if ((atomic_read(&dev->refcnt) == 1) &&
-           test_bit(ATM_DF_CLOSE,&dev->flags))
-               shutdown_atm_dev(dev);
+       if (atomic_dec_and_test(&dev->refcnt)) {
+               BUG_ON(!test_bit(ATM_DF_REMOVED, &dev->flags));
+               if (dev->ops->dev_close)
+                       dev->ops->dev_close(dev);
+               kfree(dev);
+       }
 }
 
 
diff --git a/net/atm/common.c b/net/atm/common.c
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -221,6 +221,29 @@ void vcc_release_async(struct atm_vcc *v
 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 
                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;
        }
diff --git a/net/atm/common.h b/net/atm/common.h
--- 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
--- a/net/atm/resources.c
+++ b/net/atm/resources.c
@@ -70,6 +70,7 @@ struct atm_dev *atm_dev_lookup(int numbe
        return dev;
 }
 
+
 struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops 
*ops,
                                 int number, unsigned long *flags)
 {
@@ -123,37 +124,22 @@ struct atm_dev *atm_dev_register(const c
 
 void atm_dev_deregister(struct atm_dev *dev)
 {
-       unsigned long warning_time;
-
-       atm_proc_dev_deregister(dev);
+       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);
 
-        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);
-}
+       atm_dev_release_vccs(dev);
+       atm_proc_dev_deregister(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);
 }
 
 
@@ -433,4 +419,3 @@ void *atm_dev_seq_next(struct seq_file *
 EXPORT_SYMBOL(atm_dev_register);
 EXPORT_SYMBOL(atm_dev_deregister);
 EXPORT_SYMBOL(atm_dev_lookup);
-EXPORT_SYMBOL(shutdown_atm_dev);
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to