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 | |
| parent | 64d8d46f5f501a19aec4db7ff93faf1b831d05ed (diff) | |
pcmcia: protect s->device_count
Tested-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
| -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); |
