lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Sun, 10 Oct 2010 16:55:55 +0200 (CEST) From: Stefan Richter <stefanr@...6.in-berlin.de> To: linux1394-devel@...ts.sourceforge.net cc: linux-kernel@...r.kernel.org, Tejun Heo <tj@...nel.org> Subject: [PATCH] firewire: core: use non-reentrant workqueue where necessary firewire-core manages the following types of work items: fw_card.br_work: - resets the bus on a card and possibly sends a PHY packet before that - does not sleep for long or not at all - is scheduled via fw_schedule_bus_reset() by - firewire-ohci's pci_probe method - firewire-ohci's set_config_rom method, called by kernelspace protocol drivers and userspace drivers which add/remove Configuration ROM descriptors - userspace drivers which use the bus reset ioctl - itself if the last reset happened less than 2 seconds ago - should not be executed in parallel by multiple CPUs but was not strictly protected against that fw_card.bm_work: - performs bus management duties - usually does not (but may in corner cases) sleep for long - is scheduled via fw_schedule_bm_work() by - firewire-ohci's self-ID-complete IRQ handler tasklet - firewire-core's fw_device.work instances whenever the root node device was (successfully or unsuccessfully) discovered, refreshed, or rediscovered - itself in case of resource allocation failures or in order to obey the 125ms bus manager arbitration interval - must not be executed in parallel by multiple CPUs but was not strictly protected against that fw_device.work: - performs node probe, update, shutdown, revival, removal; including kernel driver probe, update, shutdown and bus reset notification to userspace drivers - usually sleeps moderately long, in corner cases very long - is scheduled by - firewire-ohci's self-ID-complete IRQ handler tasklet via the core's fw_node_event - firewire-ohci's pci_remove method via core's fw_destroy_nodes/ fw_node_event - itself during retries, e.g. while a node is powering up - must not be executed in parallel by multiple CPUs but was not strictly protected against that iso_resource.work: - accesses registers at the Isochronous Resource Manager node - usually does not (but may in corner cases) sleep for long - is scheduled via schedule_iso_resource() by - the owning userspace driver at addition and removal of the resource - firewire-core's fw_device.work instances after bus reset - itself in case of resource allocation if necessary to obey the 1000ms reallocation period after bus reset - must not be executed in parallel by multiple CPUs but was not strictly protected against that Therefore queue all of these types of work items on system_nrt_wq instead of system_wq. The former guarantees non-reentrance across all CPUs, the latter only on the CPU which schedules a work item. As a bonus, other subsystems which flush system_wq won't be held up if the firewire subsystem spends a lot of time in an extraordinarily long fw_device.work. Signed-off-by: Stefan Richter <stefanr@...6.in-berlin.de> --- drivers/firewire/core-card.c | 6 +++--- drivers/firewire/core-cdev.c | 2 +- drivers/firewire/core-device.c | 28 +++++++++++++++++----------- 3 files changed, 21 insertions(+), 15 deletions(-) Index: b/drivers/firewire/core-card.c =================================================================== --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -219,8 +219,8 @@ void fw_schedule_bus_reset(struct fw_car /* Use an arbitrary short delay to combine multiple reset requests. */ fw_card_get(card); - if (!schedule_delayed_work(&card->br_work, - delayed ? DIV_ROUND_UP(HZ, 100) : 0)) + if (!queue_delayed_work(system_nrt_wq, &card->br_work, + delayed ? DIV_ROUND_UP(HZ, 100) : 0)) fw_card_put(card); } EXPORT_SYMBOL(fw_schedule_bus_reset); @@ -232,7 +232,7 @@ static void br_work(struct work_struct * /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */ if (card->reset_jiffies != 0 && time_is_after_jiffies(card->reset_jiffies + 2 * HZ)) { - if (!schedule_delayed_work(&card->br_work, 2 * HZ)) + if (!queue_delayed_work(system_nrt_wq, &card->br_work, 2 * HZ)) fw_card_put(card); return; } Index: b/drivers/firewire/core-cdev.c =================================================================== --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -149,7 +149,7 @@ static void release_iso_resource(struct static void schedule_iso_resource(struct iso_resource *r, unsigned long delay) { client_get(r->client); - if (!schedule_delayed_work(&r->work, delay)) + if (!queue_delayed_work(system_nrt_wq, &r->work, delay)) client_put(r->client); } Index: b/drivers/firewire/core-device.c =================================================================== --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -725,6 +725,12 @@ struct fw_device *fw_device_get_by_devt( return device; } +static void fw_schedule_device_work(struct fw_device *device, + unsigned long delay) +{ + queue_delayed_work(system_nrt_wq, &device->work, delay); +} + /* * These defines control the retry behavior for reading the config * rom. It shouldn't be necessary to tweak these; if the device @@ -749,7 +755,7 @@ static void fw_device_shutdown(struct wo if (time_is_after_jiffies(device->card->reset_jiffies + SHUTDOWN_DELAY) && !list_empty(&device->card->link)) { - schedule_delayed_work(&device->work, SHUTDOWN_DELAY); + fw_schedule_device_work(device, SHUTDOWN_DELAY); return; } @@ -861,7 +867,7 @@ static int lookup_existing_device(struct fw_notify("rediscovered device %s\n", dev_name(dev)); PREPARE_DELAYED_WORK(&old->work, fw_device_update); - schedule_delayed_work(&old->work, 0); + fw_schedule_device_work(old, 0); if (current_node == card->root_node) fw_schedule_bm_work(card, 0); @@ -952,7 +958,7 @@ static void fw_device_init(struct work_s if (device->config_rom_retries < MAX_RETRIES && atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { device->config_rom_retries++; - schedule_delayed_work(&device->work, RETRY_DELAY); + fw_schedule_device_work(device, RETRY_DELAY); } else { fw_notify("giving up on config rom for node id %x\n", device->node_id); @@ -1017,7 +1023,7 @@ static void fw_device_init(struct work_s FW_DEVICE_INITIALIZING, FW_DEVICE_RUNNING) == FW_DEVICE_GONE) { PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); - schedule_delayed_work(&device->work, SHUTDOWN_DELAY); + fw_schedule_device_work(device, SHUTDOWN_DELAY); } else { if (device->config_rom_retries) fw_notify("created device %s: GUID %08x%08x, S%d00, " @@ -1096,7 +1102,7 @@ static void fw_device_refresh(struct wor if (device->config_rom_retries < MAX_RETRIES / 2 && atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { device->config_rom_retries++; - schedule_delayed_work(&device->work, RETRY_DELAY / 2); + fw_schedule_device_work(device, RETRY_DELAY / 2); return; } @@ -1129,7 +1135,7 @@ static void fw_device_refresh(struct wor if (device->config_rom_retries < MAX_RETRIES && atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { device->config_rom_retries++; - schedule_delayed_work(&device->work, RETRY_DELAY); + fw_schedule_device_work(device, RETRY_DELAY); return; } @@ -1156,7 +1162,7 @@ static void fw_device_refresh(struct wor gone: atomic_set(&device->state, FW_DEVICE_GONE); PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); - schedule_delayed_work(&device->work, SHUTDOWN_DELAY); + fw_schedule_device_work(device, SHUTDOWN_DELAY); out: if (node_id == card->root_node->node_id) fw_schedule_bm_work(card, 0); @@ -1209,7 +1215,7 @@ void fw_node_event(struct fw_card *card, * first config rom scan half a second after bus reset. */ INIT_DELAYED_WORK(&device->work, fw_device_init); - schedule_delayed_work(&device->work, INITIAL_DELAY); + fw_schedule_device_work(device, INITIAL_DELAY); break; case FW_NODE_INITIATED_RESET: @@ -1224,7 +1230,7 @@ void fw_node_event(struct fw_card *card, FW_DEVICE_RUNNING, FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) { PREPARE_DELAYED_WORK(&device->work, fw_device_refresh); - schedule_delayed_work(&device->work, + fw_schedule_device_work(device, device->is_local ? 0 : INITIAL_DELAY); } break; @@ -1239,7 +1245,7 @@ void fw_node_event(struct fw_card *card, device->generation = card->generation; if (atomic_read(&device->state) == FW_DEVICE_RUNNING) { PREPARE_DELAYED_WORK(&device->work, fw_device_update); - schedule_delayed_work(&device->work, 0); + fw_schedule_device_work(device, 0); } break; @@ -1264,7 +1270,7 @@ void fw_node_event(struct fw_card *card, if (atomic_xchg(&device->state, FW_DEVICE_GONE) == FW_DEVICE_RUNNING) { PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); - schedule_delayed_work(&device->work, + fw_schedule_device_work(device, list_empty(&card->link) ? 0 : SHUTDOWN_DELAY); } break; -- Stefan Richter -=====-==-=- =-=- -=-=- http://arcgraph.de/sr/ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists