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