Commit e6e4f397 authored by Dominik Brodowski's avatar Dominik Brodowski

pcmcia: protect s->device_count

Tested-by: default avatarWolfram Sang <w.sang@pengutronix.de>
Signed-off-by: default avatarDominik Brodowski <linux@dominikbrodowski.net>
parent 64d8d46f
...@@ -265,6 +265,7 @@ static int pcmcia_device_probe(struct device *dev) ...@@ -265,6 +265,7 @@ static int pcmcia_device_probe(struct device *dev)
struct pcmcia_device_id *did; struct pcmcia_device_id *did;
struct pcmcia_socket *s; struct pcmcia_socket *s;
cistpl_config_t cis_config; cistpl_config_t cis_config;
unsigned long flags;
int ret = 0; int ret = 0;
dev = get_device(dev); dev = get_device(dev);
...@@ -315,9 +316,11 @@ static int pcmcia_device_probe(struct device *dev) ...@@ -315,9 +316,11 @@ static int pcmcia_device_probe(struct device *dev)
goto put_module; goto put_module;
} }
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
(p_dev->socket->device_count == 1) && (p_dev->device_no == 0)) (p_dev->socket->device_count == 1) && (p_dev->device_no == 0))
pcmcia_add_device_later(p_dev->socket, 0); pcmcia_add_device_later(p_dev->socket, 0);
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
put_module: put_module:
if (ret) if (ret)
...@@ -342,10 +345,12 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le ...@@ -342,10 +345,12 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le
"pcmcia_card_remove(%d) %s\n", s->sock, "pcmcia_card_remove(%d) %s\n", s->sock,
leftover ? leftover->devname : ""); leftover ? leftover->devname : "");
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
if (!leftover) if (!leftover)
s->device_count = 0; s->device_count = 0;
else else
s->device_count = 1; s->device_count = 1;
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
/* unregister all pcmcia_devices registered with this socket, except leftover */ /* unregister all pcmcia_devices registered with this socket, except leftover */
list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) { list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) {
...@@ -382,7 +387,7 @@ static int pcmcia_device_remove(struct device *dev) ...@@ -382,7 +387,7 @@ static int pcmcia_device_remove(struct device *dev)
*/ */
did = dev_get_drvdata(&p_dev->dev); did = dev_get_drvdata(&p_dev->dev);
if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
(p_dev->socket->device_count != 0) && (p_dev->socket->device_count > 0) &&
(p_dev->device_no == 0)) (p_dev->device_no == 0))
pcmcia_card_remove(p_dev->socket, p_dev); pcmcia_card_remove(p_dev->socket, p_dev);
...@@ -512,16 +517,19 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu ...@@ -512,16 +517,19 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
pr_debug("adding device to %d, function %d\n", s->sock, function); pr_debug("adding device to %d, function %d\n", s->sock, function);
/* max of 4 devices per card */
if (s->device_count == 4)
goto err_put;
p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL); p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
if (!p_dev) if (!p_dev)
goto err_put; goto err_put;
p_dev->socket = s; spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
p_dev->device_no = (s->device_count++); p_dev->device_no = (s->device_count++);
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
/* max of 4 devices per card */
if (p_dev->device_no >= 4)
goto err_free;
p_dev->socket = s;
p_dev->func = function; p_dev->func = function;
p_dev->dev.bus = &pcmcia_bus_type; p_dev->dev.bus = &pcmcia_bus_type;
...@@ -586,9 +594,12 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu ...@@ -586,9 +594,12 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
err_free: err_free:
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
s->device_count--;
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
kfree(p_dev->devname); kfree(p_dev->devname);
kfree(p_dev); kfree(p_dev);
s->device_count--;
err_put: err_put:
mutex_unlock(&device_add_lock); mutex_unlock(&device_add_lock);
pcmcia_put_socket(s); pcmcia_put_socket(s);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment