[ATM]: avoid race conditions related to atm_devs list
authorStanislaw Gruszka <stf_xl@wp.pl>
Wed, 30 Nov 2005 00:16:21 +0000 (16:16 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 30 Nov 2005 00:16:21 +0000 (16:16 -0800)
Use semaphore to protect atm_devs list, as no one need access to it from
interrupt context.  Avoid race conditions between atm_dev_register(),
atm_dev_lookup() and atm_dev_deregister().  Fix double spin_unlock() bug.

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>
net/atm/common.c
net/atm/resources.c
net/atm/resources.h

index db9318f..9e016f4 100644 (file)
@@ -427,12 +427,12 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
                dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf);
        } else {
                dev = NULL;
-               spin_lock(&atm_dev_lock);
+               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);
+               up(&atm_dev_mutex);
        }
        if (!dev)
                return -ENODEV;
index 35f3ceb..ad533b0 100644 (file)
@@ -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,9 +64,9 @@ 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;
 }
 
@@ -81,11 +81,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 +105,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;
 }
@@ -129,9 +127,9 @@ void atm_dev_deregister(struct atm_dev *dev)
 
        atm_proc_dev_deregister(dev);
 
-       spin_lock(&atm_dev_lock);
+       down(&atm_dev_mutex);
        list_del(&dev->dev_list);
-       spin_unlock(&atm_dev_lock);
+       up(&atm_dev_mutex);
 
         warning_time = jiffies;
         while (atomic_read(&dev->refcnt) != 1) {
@@ -211,16 +209,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 +226,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;
@@ -415,13 +413,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)
index 1291061..b7fb82a 100644 (file)
@@ -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);