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 Original line 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);
		dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf);
	} else {
	} else {
		dev = NULL;
		dev = NULL;
		spin_lock(&atm_dev_lock);
		down(&atm_dev_mutex);
		if (!list_empty(&atm_devs)) {
		if (!list_empty(&atm_devs)) {
			dev = list_entry(atm_devs.next, struct atm_dev, dev_list);
			dev = list_entry(atm_devs.next, struct atm_dev, dev_list);
			atm_dev_hold(dev);
			atm_dev_hold(dev);
		}
		}
		spin_unlock(&atm_dev_lock);
		up(&atm_dev_mutex);
	}
	}
	if (!dev)
	if (!dev)
		return -ENODEV;
		return -ENODEV;
+17 −19
Original line number Original line Diff line number Diff line
@@ -25,7 +25,7 @@




LIST_HEAD(atm_devs);
LIST_HEAD(atm_devs);
DEFINE_SPINLOCK(atm_dev_lock);
DECLARE_MUTEX(atm_dev_mutex);


static struct atm_dev *__alloc_atm_dev(const char *type)
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) {
	list_for_each(p, &atm_devs) {
		dev = list_entry(p, struct atm_dev, dev_list);
		dev = list_entry(p, struct atm_dev, dev_list);
		if ((dev->ops) && (dev->number == number)) {
		if (dev->number == number) {
			atm_dev_hold(dev);
			atm_dev_hold(dev);
			return dev;
			return dev;
		}
		}
@@ -64,9 +64,9 @@ struct atm_dev *atm_dev_lookup(int number)
{
{
	struct atm_dev *dev;
	struct atm_dev *dev;


	spin_lock(&atm_dev_lock);
	down(&atm_dev_mutex);
	dev = __atm_dev_lookup(number);
	dev = __atm_dev_lookup(number);
	spin_unlock(&atm_dev_lock);
	up(&atm_dev_mutex);
	return dev;
	return dev;
}
}


@@ -81,11 +81,11 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
		    type);
		    type);
		return NULL;
		return NULL;
	}
	}
	spin_lock(&atm_dev_lock);
	down(&atm_dev_mutex);
	if (number != -1) {
	if (number != -1) {
		if ((inuse = __atm_dev_lookup(number))) {
		if ((inuse = __atm_dev_lookup(number))) {
			atm_dev_put(inuse);
			atm_dev_put(inuse);
			spin_unlock(&atm_dev_lock);
			up(&atm_dev_mutex);
			kfree(dev);
			kfree(dev);
			return NULL;
			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->flags, 0, sizeof(dev->flags));
	memset(&dev->stats, 0, sizeof(dev->stats));
	memset(&dev->stats, 0, sizeof(dev->stats));
	atomic_set(&dev->refcnt, 1);
	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) {
	if (atm_proc_dev_register(dev) < 0) {
		printk(KERN_ERR "atm_dev_register: "
		printk(KERN_ERR "atm_dev_register: "
		       "atm_proc_dev_register failed for dev %s\n",
		       "atm_proc_dev_register failed for dev %s\n",
		       type);
		       type);
		spin_lock(&atm_dev_lock);
		up(&atm_dev_mutex);
		list_del(&dev->dev_list);
		spin_unlock(&atm_dev_lock);
		kfree(dev);
		kfree(dev);
		return NULL;
		return NULL;
	}
	}
	list_add_tail(&dev->dev_list, &atm_devs);
	up(&atm_dev_mutex);


	return dev;
	return dev;
}
}
@@ -129,9 +127,9 @@ void atm_dev_deregister(struct atm_dev *dev)


	atm_proc_dev_deregister(dev);
	atm_proc_dev_deregister(dev);


	spin_lock(&atm_dev_lock);
	down(&atm_dev_mutex);
	list_del(&dev->dev_list);
	list_del(&dev->dev_list);
	spin_unlock(&atm_dev_lock);
	up(&atm_dev_mutex);


        warning_time = jiffies;
        warning_time = jiffies;
        while (atomic_read(&dev->refcnt) != 1) {
        while (atomic_read(&dev->refcnt) != 1) {
@@ -211,16 +209,16 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg)
				return -EFAULT;
				return -EFAULT;
			if (get_user(len, &iobuf->length))
			if (get_user(len, &iobuf->length))
				return -EFAULT;
				return -EFAULT;
			spin_lock(&atm_dev_lock);
			down(&atm_dev_mutex);
			list_for_each(p, &atm_devs)
			list_for_each(p, &atm_devs)
				size += sizeof(int);
				size += sizeof(int);
			if (size > len) {
			if (size > len) {
				spin_unlock(&atm_dev_lock);
				up(&atm_dev_mutex);
				return -E2BIG;
				return -E2BIG;
			}
			}
			tmp_buf = kmalloc(size, GFP_ATOMIC);
			tmp_buf = kmalloc(size, GFP_ATOMIC);
			if (!tmp_buf) {
			if (!tmp_buf) {
				spin_unlock(&atm_dev_lock);
				up(&atm_dev_mutex);
				return -ENOMEM;
				return -ENOMEM;
			}
			}
			tmp_p = tmp_buf;
			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);
				dev = list_entry(p, struct atm_dev, dev_list);
				*tmp_p++ = dev->number;
				*tmp_p++ = dev->number;
			}
			}
			spin_unlock(&atm_dev_lock);
			up(&atm_dev_mutex);
		        error = ((copy_to_user(buf, tmp_buf, size)) ||
		        error = ((copy_to_user(buf, tmp_buf, size)) ||
					put_user(size, &iobuf->length))
					put_user(size, &iobuf->length))
						? -EFAULT : 0;
						? -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)
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;
	return *pos ? dev_get_idx(*pos) : (void *) 1;
}
}


void atm_dev_seq_stop(struct seq_file *seq, void *v)
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)
void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+1 −2
Original line number Original line Diff line number Diff line
@@ -11,8 +11,7 @@




extern struct list_head atm_devs;
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);
int atm_dev_ioctl(unsigned int cmd, void __user *arg);