diff options
| author | Stanislaw Gruszka <stf_xl@wp.pl> | 2005-11-29 19:16:21 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2005-11-29 19:16:21 -0500 |
| commit | aaaaaadbe7a663d110814db50fcbe7d320eb4c32 (patch) | |
| tree | 316bdbd49e3a6ac7a78cad8797d148f79a343d45 | |
| parent | 49693280262a149e5430d3401e263e464c88334a (diff) | |
[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>
| -rw-r--r-- | net/atm/common.c | 4 | ||||
| -rw-r--r-- | net/atm/resources.c | 36 | ||||
| -rw-r--r-- | net/atm/resources.h | 3 |
3 files changed, 20 insertions, 23 deletions
diff --git a/net/atm/common.c b/net/atm/common.c index db9318fc6031..9e016f404e14 100644 --- a/net/atm/common.c +++ b/net/atm/common.c | |||
| @@ -427,12 +427,12 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci) | |||
| 427 | dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf); | 427 | dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf); |
| 428 | } else { | 428 | } else { |
| 429 | dev = NULL; | 429 | dev = NULL; |
| 430 | spin_lock(&atm_dev_lock); | 430 | down(&atm_dev_mutex); |
| 431 | if (!list_empty(&atm_devs)) { | 431 | if (!list_empty(&atm_devs)) { |
| 432 | dev = list_entry(atm_devs.next, struct atm_dev, dev_list); | 432 | dev = list_entry(atm_devs.next, struct atm_dev, dev_list); |
| 433 | atm_dev_hold(dev); | 433 | atm_dev_hold(dev); |
| 434 | } | 434 | } |
| 435 | spin_unlock(&atm_dev_lock); | 435 | up(&atm_dev_mutex); |
| 436 | } | 436 | } |
| 437 | if (!dev) | 437 | if (!dev) |
| 438 | return -ENODEV; | 438 | return -ENODEV; |
diff --git a/net/atm/resources.c b/net/atm/resources.c index 35f3ceb76868..ad533b02b84f 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c | |||
| @@ -25,7 +25,7 @@ | |||
| 25 | 25 | ||
| 26 | 26 | ||
| 27 | LIST_HEAD(atm_devs); | 27 | LIST_HEAD(atm_devs); |
| 28 | DEFINE_SPINLOCK(atm_dev_lock); | 28 | DECLARE_MUTEX(atm_dev_mutex); |
| 29 | 29 | ||
| 30 | static struct atm_dev *__alloc_atm_dev(const char *type) | 30 | static struct atm_dev *__alloc_atm_dev(const char *type) |
| 31 | { | 31 | { |
| @@ -52,7 +52,7 @@ static struct atm_dev *__atm_dev_lookup(int number) | |||
| 52 | 52 | ||
| 53 | list_for_each(p, &atm_devs) { | 53 | list_for_each(p, &atm_devs) { |
| 54 | dev = list_entry(p, struct atm_dev, dev_list); | 54 | dev = list_entry(p, struct atm_dev, dev_list); |
| 55 | if ((dev->ops) && (dev->number == number)) { | 55 | if (dev->number == number) { |
| 56 | atm_dev_hold(dev); | 56 | atm_dev_hold(dev); |
| 57 | return dev; | 57 | return dev; |
| 58 | } | 58 | } |
| @@ -64,9 +64,9 @@ struct atm_dev *atm_dev_lookup(int number) | |||
| 64 | { | 64 | { |
| 65 | struct atm_dev *dev; | 65 | struct atm_dev *dev; |
| 66 | 66 | ||
| 67 | spin_lock(&atm_dev_lock); | 67 | down(&atm_dev_mutex); |
| 68 | dev = __atm_dev_lookup(number); | 68 | dev = __atm_dev_lookup(number); |
| 69 | spin_unlock(&atm_dev_lock); | 69 | up(&atm_dev_mutex); |
| 70 | return dev; | 70 | return dev; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| @@ -81,11 +81,11 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, | |||
| 81 | type); | 81 | type); |
| 82 | return NULL; | 82 | return NULL; |
| 83 | } | 83 | } |
| 84 | spin_lock(&atm_dev_lock); | 84 | down(&atm_dev_mutex); |
| 85 | if (number != -1) { | 85 | if (number != -1) { |
| 86 | if ((inuse = __atm_dev_lookup(number))) { | 86 | if ((inuse = __atm_dev_lookup(number))) { |
| 87 | atm_dev_put(inuse); | 87 | atm_dev_put(inuse); |
| 88 | spin_unlock(&atm_dev_lock); | 88 | up(&atm_dev_mutex); |
| 89 | kfree(dev); | 89 | kfree(dev); |
| 90 | return NULL; | 90 | return NULL; |
| 91 | } | 91 | } |
| @@ -105,19 +105,17 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, | |||
| 105 | memset(&dev->flags, 0, sizeof(dev->flags)); | 105 | memset(&dev->flags, 0, sizeof(dev->flags)); |
| 106 | memset(&dev->stats, 0, sizeof(dev->stats)); | 106 | memset(&dev->stats, 0, sizeof(dev->stats)); |
| 107 | atomic_set(&dev->refcnt, 1); | 107 | atomic_set(&dev->refcnt, 1); |
| 108 | list_add_tail(&dev->dev_list, &atm_devs); | ||
| 109 | spin_unlock(&atm_dev_lock); | ||
| 110 | 108 | ||
| 111 | if (atm_proc_dev_register(dev) < 0) { | 109 | if (atm_proc_dev_register(dev) < 0) { |
| 112 | printk(KERN_ERR "atm_dev_register: " | 110 | printk(KERN_ERR "atm_dev_register: " |
| 113 | "atm_proc_dev_register failed for dev %s\n", | 111 | "atm_proc_dev_register failed for dev %s\n", |
| 114 | type); | 112 | type); |
| 115 | spin_lock(&atm_dev_lock); | 113 | up(&atm_dev_mutex); |
| 116 | list_del(&dev->dev_list); | ||
| 117 | spin_unlock(&atm_dev_lock); | ||
| 118 | kfree(dev); | 114 | kfree(dev); |
| 119 | return NULL; | 115 | return NULL; |
| 120 | } | 116 | } |
| 117 | list_add_tail(&dev->dev_list, &atm_devs); | ||
| 118 | up(&atm_dev_mutex); | ||
| 121 | 119 | ||
| 122 | return dev; | 120 | return dev; |
| 123 | } | 121 | } |
| @@ -129,9 +127,9 @@ void atm_dev_deregister(struct atm_dev *dev) | |||
| 129 | 127 | ||
| 130 | atm_proc_dev_deregister(dev); | 128 | atm_proc_dev_deregister(dev); |
| 131 | 129 | ||
| 132 | spin_lock(&atm_dev_lock); | 130 | down(&atm_dev_mutex); |
| 133 | list_del(&dev->dev_list); | 131 | list_del(&dev->dev_list); |
| 134 | spin_unlock(&atm_dev_lock); | 132 | up(&atm_dev_mutex); |
| 135 | 133 | ||
| 136 | warning_time = jiffies; | 134 | warning_time = jiffies; |
| 137 | while (atomic_read(&dev->refcnt) != 1) { | 135 | while (atomic_read(&dev->refcnt) != 1) { |
| @@ -211,16 +209,16 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
| 211 | return -EFAULT; | 209 | return -EFAULT; |
| 212 | if (get_user(len, &iobuf->length)) | 210 | if (get_user(len, &iobuf->length)) |
| 213 | return -EFAULT; | 211 | return -EFAULT; |
| 214 | spin_lock(&atm_dev_lock); | 212 | down(&atm_dev_mutex); |
| 215 | list_for_each(p, &atm_devs) | 213 | list_for_each(p, &atm_devs) |
| 216 | size += sizeof(int); | 214 | size += sizeof(int); |
| 217 | if (size > len) { | 215 | if (size > len) { |
| 218 | spin_unlock(&atm_dev_lock); | 216 | up(&atm_dev_mutex); |
| 219 | return -E2BIG; | 217 | return -E2BIG; |
| 220 | } | 218 | } |
| 221 | tmp_buf = kmalloc(size, GFP_ATOMIC); | 219 | tmp_buf = kmalloc(size, GFP_ATOMIC); |
| 222 | if (!tmp_buf) { | 220 | if (!tmp_buf) { |
| 223 | spin_unlock(&atm_dev_lock); | 221 | up(&atm_dev_mutex); |
| 224 | return -ENOMEM; | 222 | return -ENOMEM; |
| 225 | } | 223 | } |
| 226 | tmp_p = tmp_buf; | 224 | tmp_p = tmp_buf; |
| @@ -228,7 +226,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
| 228 | dev = list_entry(p, struct atm_dev, dev_list); | 226 | dev = list_entry(p, struct atm_dev, dev_list); |
| 229 | *tmp_p++ = dev->number; | 227 | *tmp_p++ = dev->number; |
| 230 | } | 228 | } |
| 231 | spin_unlock(&atm_dev_lock); | 229 | up(&atm_dev_mutex); |
| 232 | error = ((copy_to_user(buf, tmp_buf, size)) || | 230 | error = ((copy_to_user(buf, tmp_buf, size)) || |
| 233 | put_user(size, &iobuf->length)) | 231 | put_user(size, &iobuf->length)) |
| 234 | ? -EFAULT : 0; | 232 | ? -EFAULT : 0; |
| @@ -415,13 +413,13 @@ static __inline__ void *dev_get_idx(loff_t left) | |||
| 415 | 413 | ||
| 416 | void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) | 414 | void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) |
| 417 | { | 415 | { |
| 418 | spin_lock(&atm_dev_lock); | 416 | down(&atm_dev_mutex); |
| 419 | return *pos ? dev_get_idx(*pos) : (void *) 1; | 417 | return *pos ? dev_get_idx(*pos) : (void *) 1; |
| 420 | } | 418 | } |
| 421 | 419 | ||
| 422 | void atm_dev_seq_stop(struct seq_file *seq, void *v) | 420 | void atm_dev_seq_stop(struct seq_file *seq, void *v) |
| 423 | { | 421 | { |
| 424 | spin_unlock(&atm_dev_lock); | 422 | up(&atm_dev_mutex); |
| 425 | } | 423 | } |
| 426 | 424 | ||
| 427 | void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 425 | void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
diff --git a/net/atm/resources.h b/net/atm/resources.h index 12910619dbb6..b7fb82a93b42 100644 --- a/net/atm/resources.h +++ b/net/atm/resources.h | |||
| @@ -11,8 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | extern struct list_head atm_devs; | 13 | extern struct list_head atm_devs; |
| 14 | extern spinlock_t atm_dev_lock; | 14 | extern struct semaphore atm_dev_mutex; |
| 15 | |||
| 16 | 15 | ||
| 17 | int atm_dev_ioctl(unsigned int cmd, void __user *arg); | 16 | int atm_dev_ioctl(unsigned int cmd, void __user *arg); |
| 18 | 17 | ||
