diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-01-15 19:34:06 -0500 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-02-17 11:48:18 -0500 |
commit | e6e4f397e5d0970ee1bb7a5591ac93b37cfa524a (patch) | |
tree | 8e20dc8b8281ee4a6e7782554825212d93983de7 /drivers/pcmcia/ds.c | |
parent | 64d8d46f5f501a19aec4db7ff93faf1b831d05ed (diff) |
pcmcia: protect s->device_count
Tested-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers/pcmcia/ds.c')
-rw-r--r-- | drivers/pcmcia/ds.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 4f7308df22c8..bcb9ef103427 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -265,6 +265,7 @@ static int pcmcia_device_probe(struct device *dev) | |||
265 | struct pcmcia_device_id *did; | 265 | struct pcmcia_device_id *did; |
266 | struct pcmcia_socket *s; | 266 | struct pcmcia_socket *s; |
267 | cistpl_config_t cis_config; | 267 | cistpl_config_t cis_config; |
268 | unsigned long flags; | ||
268 | int ret = 0; | 269 | int ret = 0; |
269 | 270 | ||
270 | dev = get_device(dev); | 271 | dev = get_device(dev); |
@@ -315,9 +316,11 @@ static int pcmcia_device_probe(struct device *dev) | |||
315 | goto put_module; | 316 | goto put_module; |
316 | } | 317 | } |
317 | 318 | ||
319 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
318 | if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && | 320 | if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && |
319 | (p_dev->socket->device_count == 1) && (p_dev->device_no == 0)) | 321 | (p_dev->socket->device_count == 1) && (p_dev->device_no == 0)) |
320 | pcmcia_add_device_later(p_dev->socket, 0); | 322 | pcmcia_add_device_later(p_dev->socket, 0); |
323 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
321 | 324 | ||
322 | put_module: | 325 | put_module: |
323 | if (ret) | 326 | if (ret) |
@@ -342,10 +345,12 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le | |||
342 | "pcmcia_card_remove(%d) %s\n", s->sock, | 345 | "pcmcia_card_remove(%d) %s\n", s->sock, |
343 | leftover ? leftover->devname : ""); | 346 | leftover ? leftover->devname : ""); |
344 | 347 | ||
348 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
345 | if (!leftover) | 349 | if (!leftover) |
346 | s->device_count = 0; | 350 | s->device_count = 0; |
347 | else | 351 | else |
348 | s->device_count = 1; | 352 | s->device_count = 1; |
353 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
349 | 354 | ||
350 | /* unregister all pcmcia_devices registered with this socket, except leftover */ | 355 | /* unregister all pcmcia_devices registered with this socket, except leftover */ |
351 | list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) { | 356 | 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 | */ | 387 | */ |
383 | did = dev_get_drvdata(&p_dev->dev); | 388 | did = dev_get_drvdata(&p_dev->dev); |
384 | if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && | 389 | if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && |
385 | (p_dev->socket->device_count != 0) && | 390 | (p_dev->socket->device_count > 0) && |
386 | (p_dev->device_no == 0)) | 391 | (p_dev->device_no == 0)) |
387 | pcmcia_card_remove(p_dev->socket, p_dev); | 392 | pcmcia_card_remove(p_dev->socket, p_dev); |
388 | 393 | ||
@@ -512,16 +517,19 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu | |||
512 | 517 | ||
513 | pr_debug("adding device to %d, function %d\n", s->sock, function); | 518 | pr_debug("adding device to %d, function %d\n", s->sock, function); |
514 | 519 | ||
515 | /* max of 4 devices per card */ | ||
516 | if (s->device_count == 4) | ||
517 | goto err_put; | ||
518 | |||
519 | p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL); | 520 | p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL); |
520 | if (!p_dev) | 521 | if (!p_dev) |
521 | goto err_put; | 522 | goto err_put; |
522 | 523 | ||
523 | p_dev->socket = s; | 524 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); |
524 | p_dev->device_no = (s->device_count++); | 525 | p_dev->device_no = (s->device_count++); |
526 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
527 | |||
528 | /* max of 4 devices per card */ | ||
529 | if (p_dev->device_no >= 4) | ||
530 | goto err_free; | ||
531 | |||
532 | p_dev->socket = s; | ||
525 | p_dev->func = function; | 533 | p_dev->func = function; |
526 | 534 | ||
527 | p_dev->dev.bus = &pcmcia_bus_type; | 535 | 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 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | 594 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); |
587 | 595 | ||
588 | err_free: | 596 | err_free: |
597 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
598 | s->device_count--; | ||
599 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
600 | |||
589 | kfree(p_dev->devname); | 601 | kfree(p_dev->devname); |
590 | kfree(p_dev); | 602 | kfree(p_dev); |
591 | s->device_count--; | ||
592 | err_put: | 603 | err_put: |
593 | mutex_unlock(&device_add_lock); | 604 | mutex_unlock(&device_add_lock); |
594 | pcmcia_put_socket(s); | 605 | pcmcia_put_socket(s); |