Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aaaaaadb authored by Stanislaw Gruszka's avatar Stanislaw Gruszka Committed by David S. Miller
Browse files

[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: default avatarStanislaw Gruszka <stf_xl@wp.pl>
Signed-off-by: default avatarChas Williams <chas@cmf.nrl.navy.mil>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 49693280
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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;
+17 −19
Original line number Diff line number Diff line
@@ -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)
+1 −2
Original line number Diff line number Diff line
@@ -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);