[ATM]: avoid race conditions related to atm_devs list

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>

authored by Stanislaw Gruszka and committed by David S. Miller aaaaaadb 49693280

+20 -23
+2 -2
net/atm/common.c
··· 427 427 dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf); 428 428 } else { 429 429 dev = NULL; 430 - spin_lock(&atm_dev_lock); 430 + down(&atm_dev_mutex); 431 431 if (!list_empty(&atm_devs)) { 432 432 dev = list_entry(atm_devs.next, struct atm_dev, dev_list); 433 433 atm_dev_hold(dev); 434 434 } 435 - spin_unlock(&atm_dev_lock); 435 + up(&atm_dev_mutex); 436 436 } 437 437 if (!dev) 438 438 return -ENODEV;
+17 -19
net/atm/resources.c
··· 25 25 26 26 27 27 LIST_HEAD(atm_devs); 28 - DEFINE_SPINLOCK(atm_dev_lock); 28 + DECLARE_MUTEX(atm_dev_mutex); 29 29 30 30 static struct atm_dev *__alloc_atm_dev(const char *type) 31 31 { ··· 52 52 53 53 list_for_each(p, &atm_devs) { 54 54 dev = list_entry(p, struct atm_dev, dev_list); 55 - if ((dev->ops) && (dev->number == number)) { 55 + if (dev->number == number) { 56 56 atm_dev_hold(dev); 57 57 return dev; 58 58 } ··· 64 64 { 65 65 struct atm_dev *dev; 66 66 67 - spin_lock(&atm_dev_lock); 67 + down(&atm_dev_mutex); 68 68 dev = __atm_dev_lookup(number); 69 - spin_unlock(&atm_dev_lock); 69 + up(&atm_dev_mutex); 70 70 return dev; 71 71 } 72 72 ··· 81 81 type); 82 82 return NULL; 83 83 } 84 - spin_lock(&atm_dev_lock); 84 + down(&atm_dev_mutex); 85 85 if (number != -1) { 86 86 if ((inuse = __atm_dev_lookup(number))) { 87 87 atm_dev_put(inuse); 88 - spin_unlock(&atm_dev_lock); 88 + up(&atm_dev_mutex); 89 89 kfree(dev); 90 90 return NULL; 91 91 } ··· 105 105 memset(&dev->flags, 0, sizeof(dev->flags)); 106 106 memset(&dev->stats, 0, sizeof(dev->stats)); 107 107 atomic_set(&dev->refcnt, 1); 108 - list_add_tail(&dev->dev_list, &atm_devs); 109 - spin_unlock(&atm_dev_lock); 110 108 111 109 if (atm_proc_dev_register(dev) < 0) { 112 110 printk(KERN_ERR "atm_dev_register: " 113 111 "atm_proc_dev_register failed for dev %s\n", 114 112 type); 115 - spin_lock(&atm_dev_lock); 116 - list_del(&dev->dev_list); 117 - spin_unlock(&atm_dev_lock); 113 + up(&atm_dev_mutex); 118 114 kfree(dev); 119 115 return NULL; 120 116 } 117 + list_add_tail(&dev->dev_list, &atm_devs); 118 + up(&atm_dev_mutex); 121 119 122 120 return dev; 123 121 } ··· 127 129 128 130 atm_proc_dev_deregister(dev); 129 131 130 - spin_lock(&atm_dev_lock); 132 + down(&atm_dev_mutex); 131 133 list_del(&dev->dev_list); 132 - spin_unlock(&atm_dev_lock); 134 + up(&atm_dev_mutex); 133 135 134 136 warning_time = jiffies; 135 137 while (atomic_read(&dev->refcnt) != 1) { ··· 209 211 return -EFAULT; 210 212 if (get_user(len, &iobuf->length)) 211 213 return -EFAULT; 212 - spin_lock(&atm_dev_lock); 214 + down(&atm_dev_mutex); 213 215 list_for_each(p, &atm_devs) 214 216 size += sizeof(int); 215 217 if (size > len) { 216 - spin_unlock(&atm_dev_lock); 218 + up(&atm_dev_mutex); 217 219 return -E2BIG; 218 220 } 219 221 tmp_buf = kmalloc(size, GFP_ATOMIC); 220 222 if (!tmp_buf) { 221 - spin_unlock(&atm_dev_lock); 223 + up(&atm_dev_mutex); 222 224 return -ENOMEM; 223 225 } 224 226 tmp_p = tmp_buf; ··· 226 228 dev = list_entry(p, struct atm_dev, dev_list); 227 229 *tmp_p++ = dev->number; 228 230 } 229 - spin_unlock(&atm_dev_lock); 231 + up(&atm_dev_mutex); 230 232 error = ((copy_to_user(buf, tmp_buf, size)) || 231 233 put_user(size, &iobuf->length)) 232 234 ? -EFAULT : 0; ··· 413 415 414 416 void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) 415 417 { 416 - spin_lock(&atm_dev_lock); 418 + down(&atm_dev_mutex); 417 419 return *pos ? dev_get_idx(*pos) : (void *) 1; 418 420 } 419 421 420 422 void atm_dev_seq_stop(struct seq_file *seq, void *v) 421 423 { 422 - spin_unlock(&atm_dev_lock); 424 + up(&atm_dev_mutex); 423 425 } 424 426 425 427 void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+1 -2
net/atm/resources.h
··· 11 11 12 12 13 13 extern struct list_head atm_devs; 14 - extern spinlock_t atm_dev_lock; 15 - 14 + extern struct semaphore atm_dev_mutex; 16 15 17 16 int atm_dev_ioctl(unsigned int cmd, void __user *arg); 18 17