diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2009-06-16 13:15:25 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2009-06-16 16:48:09 -0400 |
commit | d645f4dad056a98089df904294f66b96d04e91b6 (patch) | |
tree | 993ec9d0c64dac6fb4e1214f213220fbc0e29f63 /drivers | |
parent | 29ad14cddd6246d17ff22f496363dfd6b3de8964 (diff) |
firewire: core: fix iso context shutdown on card removal
If isochronous contexts existed when firewire-ohci was unloaded, the
core iso shutdown functions crashed with NULL dereferences, and buffers
etc. weren't released.
How the fix works: We first copy the card driver's iso shutdown hooks
into the dummy driver, then fw_destroy_nodes notifies upper layers of
devices going away, these should shut down (including their iso
contexts), wait_for_completion(&card->done) will be triggered after
upper layers gave up all fw_device references, after which the card
driver's shutdown proceeds.
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firewire/core-card.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 667603ac14b1..543fccac81bb 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c | |||
@@ -461,11 +461,11 @@ EXPORT_SYMBOL(fw_card_add); | |||
461 | 461 | ||
462 | 462 | ||
463 | /* | 463 | /* |
464 | * The next few functions implements a dummy driver that use once a | 464 | * The next few functions implement a dummy driver that is used once a card |
465 | * card driver shuts down an fw_card. This allows the driver to | 465 | * driver shuts down an fw_card. This allows the driver to cleanly unload, |
466 | * cleanly unload, as all IO to the card will be handled by the dummy | 466 | * as all IO to the card will be handled (and failed) by the dummy driver |
467 | * driver instead of calling into the (possibly) unloaded module. The | 467 | * instead of calling into the module. Only functions for iso context |
468 | * dummy driver just fails all IO. | 468 | * shutdown still need to be provided by the card driver. |
469 | */ | 469 | */ |
470 | 470 | ||
471 | static int dummy_enable(struct fw_card *card, u32 *config_rom, size_t length) | 471 | static int dummy_enable(struct fw_card *card, u32 *config_rom, size_t length) |
@@ -512,7 +512,7 @@ static int dummy_enable_phys_dma(struct fw_card *card, | |||
512 | return -ENODEV; | 512 | return -ENODEV; |
513 | } | 513 | } |
514 | 514 | ||
515 | static struct fw_card_driver dummy_driver = { | 515 | static const struct fw_card_driver dummy_driver_template = { |
516 | .enable = dummy_enable, | 516 | .enable = dummy_enable, |
517 | .update_phy_reg = dummy_update_phy_reg, | 517 | .update_phy_reg = dummy_update_phy_reg, |
518 | .set_config_rom = dummy_set_config_rom, | 518 | .set_config_rom = dummy_set_config_rom, |
@@ -531,6 +531,8 @@ void fw_card_release(struct kref *kref) | |||
531 | 531 | ||
532 | void fw_core_remove_card(struct fw_card *card) | 532 | void fw_core_remove_card(struct fw_card *card) |
533 | { | 533 | { |
534 | struct fw_card_driver dummy_driver = dummy_driver_template; | ||
535 | |||
534 | card->driver->update_phy_reg(card, 4, | 536 | card->driver->update_phy_reg(card, 4, |
535 | PHY_LINK_ACTIVE | PHY_CONTENDER, 0); | 537 | PHY_LINK_ACTIVE | PHY_CONTENDER, 0); |
536 | fw_core_initiate_bus_reset(card, 1); | 538 | fw_core_initiate_bus_reset(card, 1); |
@@ -539,7 +541,9 @@ void fw_core_remove_card(struct fw_card *card) | |||
539 | list_del_init(&card->link); | 541 | list_del_init(&card->link); |
540 | mutex_unlock(&card_mutex); | 542 | mutex_unlock(&card_mutex); |
541 | 543 | ||
542 | /* Set up the dummy driver. */ | 544 | /* Switch off most of the card driver interface. */ |
545 | dummy_driver.free_iso_context = card->driver->free_iso_context; | ||
546 | dummy_driver.stop_iso = card->driver->stop_iso; | ||
543 | card->driver = &dummy_driver; | 547 | card->driver = &dummy_driver; |
544 | 548 | ||
545 | fw_destroy_nodes(card); | 549 | fw_destroy_nodes(card); |