* [PATCH] firewire: core: use non-reentrant workqueue where necessary
@ 2010-10-10 14:55 Stefan Richter
2010-10-10 14:57 ` [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown Stefan Richter
` (2 more replies)
0 siblings, 3 replies; 17+ messages in thread
From: Stefan Richter @ 2010-10-10 14:55 UTC (permalink / raw)
To: linux1394-devel; +Cc: linux-kernel, Tejun Heo
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@s5r6.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/
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown 2010-10-10 14:55 [PATCH] firewire: core: use non-reentrant workqueue where necessary Stefan Richter @ 2010-10-10 14:57 ` Stefan Richter 2010-10-11 13:43 ` Tejun Heo 2010-10-12 21:39 ` [PATCH unfinished update] " Stefan Richter 2010-10-11 13:29 ` [PATCH] firewire: core: use non-reentrant workqueue where necessary Tejun Heo 2010-10-12 21:29 ` [PATCH update] firewire: core: use non-reentrant workqueue with rescuer Stefan Richter 2 siblings, 2 replies; 17+ messages in thread From: Stefan Richter @ 2010-10-10 14:57 UTC (permalink / raw) To: linux1394-devel; +Cc: linux-kernel, Tejun Heo firewire-sbp2 used to perform management tasks (and SCSI Inquiry, sd probe etc.) in one single-threaded workqueue for all targets. Some of these jobs may take very long, e.g. when the target needs to spin up a disk to perform the task. We should have had per-target workqueues for that but didn't because that would have created respectively many kernel threads which almost always sit idle. Now that we have concurrency managed workqueues, correct that lack of parallelism: Simply swap out the driver workqueue by system_nrt_wq. It provides all the parallelism we will ever need, accepts long-running work, and provides the here necessary guarantee of non-reentrance across all CPUs. (The work items are scheduled from firewire-core's fw_device work items which themselves may change CPUs.) This simple approach requires though that targets with multiple logical units accept multiple outstanding management requests. The SBP-2 spec implicitly requires this capability, but who knows how real firmwares react. I only have access to two dual-LU targets: A OXUF924DSB based one from MacPower and a INIC-2430 based one from IOI. They both work fine with this change, as do several single-LU targets of course. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> --- drivers/firewire/sbp2.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) Index: b/drivers/firewire/sbp2.c =================================================================== --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -835,8 +835,6 @@ static void sbp2_target_put(struct sbp2_ kref_put(&tgt->kref, sbp2_release_target); } -static struct workqueue_struct *sbp2_wq; - /* * Always get the target's kref when scheduling work on one its units. * Each workqueue job is responsible to call sbp2_target_put() upon return. @@ -844,7 +842,7 @@ static struct workqueue_struct *sbp2_wq; static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) { sbp2_target_get(lu->tgt); - if (!queue_delayed_work(sbp2_wq, &lu->work, delay)) + if (!queue_delayed_work(system_nrt_wq, &lu->work, delay)) sbp2_target_put(lu->tgt); } @@ -1656,17 +1654,12 @@ MODULE_ALIAS("sbp2"); static int __init sbp2_init(void) { - sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME); - if (!sbp2_wq) - return -ENOMEM; - return driver_register(&sbp2_driver.driver); } static void __exit sbp2_cleanup(void) { driver_unregister(&sbp2_driver.driver); - destroy_workqueue(sbp2_wq); } module_init(sbp2_init); -- Stefan Richter -=====-==-=- =-=- -=-=- http://arcgraph.de/sr/ ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown 2010-10-10 14:57 ` [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown Stefan Richter @ 2010-10-11 13:43 ` Tejun Heo 2010-10-11 21:27 ` Stefan Richter 2010-10-12 21:39 ` [PATCH unfinished update] " Stefan Richter 1 sibling, 1 reply; 17+ messages in thread From: Tejun Heo @ 2010-10-11 13:43 UTC (permalink / raw) To: Stefan Richter; +Cc: linux1394-devel, linux-kernel Hello, On 10/10/2010 04:57 PM, Stefan Richter wrote: ... > Simply swap out the driver workqueue by system_nrt_wq. It provides all > the parallelism we will ever need, accepts long-running work, and > provides the here necessary guarantee of non-reentrance across all CPUs. ^^^^ this probably should go away? > (The work items are scheduled from firewire-core's fw_device work items > which themselves may change CPUs.) > > This simple approach requires though that targets with multiple logical > units accept multiple outstanding management requests. The SBP-2 spec > implicitly requires this capability, but who knows how real firmwares > react. > > I only have access to two dual-LU targets: A OXUF924DSB based one from > MacPower and a INIC-2430 based one from IOI. They both work fine with > this change, as do several single-LU targets of course. > > Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> > --- > drivers/firewire/sbp2.c | 9 +-------- > 1 file changed, 1 insertion(+), 8 deletions(-) > > Index: b/drivers/firewire/sbp2.c > =================================================================== > --- a/drivers/firewire/sbp2.c > +++ b/drivers/firewire/sbp2.c > @@ -835,8 +835,6 @@ static void sbp2_target_put(struct sbp2_ > kref_put(&tgt->kref, sbp2_release_target); > } > > -static struct workqueue_struct *sbp2_wq; > - > /* > * Always get the target's kref when scheduling work on one its units. > * Each workqueue job is responsible to call sbp2_target_put() upon return. > @@ -844,7 +842,7 @@ static struct workqueue_struct *sbp2_wq; > static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) > { > sbp2_target_get(lu->tgt); > - if (!queue_delayed_work(sbp2_wq, &lu->work, delay)) > + if (!queue_delayed_work(system_nrt_wq, &lu->work, delay)) > sbp2_target_put(lu->tgt); > } > > @@ -1656,17 +1654,12 @@ MODULE_ALIAS("sbp2"); > > static int __init sbp2_init(void) > { > - sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME); > - if (!sbp2_wq) > - return -ENOMEM; > - > return driver_register(&sbp2_driver.driver); > } > > static void __exit sbp2_cleanup(void) > { > driver_unregister(&sbp2_driver.driver); > - destroy_workqueue(sbp2_wq); Hmmm... from glancing the code, there doesn't seem to anything which can guarantee sbp2_release_target/reconnect() are finished before sbp2_cleanup() returns, so the code section might go away with code still running. It seems like the right thing to do here would be using alloc_workqueue(KBUILD_MODNAME, WQ_NON_REENTRANT, 0). Am I missing something? Thanks. -- tejun ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown 2010-10-11 13:43 ` Tejun Heo @ 2010-10-11 21:27 ` Stefan Richter 2010-10-11 21:39 ` Stefan Richter 2010-10-12 13:50 ` Tejun Heo 0 siblings, 2 replies; 17+ messages in thread From: Stefan Richter @ 2010-10-11 21:27 UTC (permalink / raw) To: Tejun Heo; +Cc: linux1394-devel, linux-kernel Tejun Heo wrote: > On 10/10/2010 04:57 PM, Stefan Richter wrote: > ... >> Simply swap out the driver workqueue by system_nrt_wq. It provides all >> the parallelism we will ever need, accepts long-running work, and >> provides the here necessary guarantee of non-reentrance across all CPUs. > ^^^^ > this probably should go away? > >> (The work items are scheduled from firewire-core's fw_device work items >> which themselves may change CPUs.) Yep. [...] >> --- a/drivers/firewire/sbp2.c >> +++ b/drivers/firewire/sbp2.c >> @@ -835,8 +835,6 @@ static void sbp2_target_put(struct sbp2_ >> kref_put(&tgt->kref, sbp2_release_target); >> } >> >> -static struct workqueue_struct *sbp2_wq; >> - >> /* >> * Always get the target's kref when scheduling work on one its units. >> * Each workqueue job is responsible to call sbp2_target_put() upon return. >> @@ -844,7 +842,7 @@ static struct workqueue_struct *sbp2_wq; >> static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) >> { >> sbp2_target_get(lu->tgt); >> - if (!queue_delayed_work(sbp2_wq, &lu->work, delay)) >> + if (!queue_delayed_work(system_nrt_wq, &lu->work, delay)) >> sbp2_target_put(lu->tgt); >> } >> >> @@ -1656,17 +1654,12 @@ MODULE_ALIAS("sbp2"); >> >> static int __init sbp2_init(void) >> { >> - sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME); >> - if (!sbp2_wq) >> - return -ENOMEM; >> - >> return driver_register(&sbp2_driver.driver); >> } >> >> static void __exit sbp2_cleanup(void) >> { >> driver_unregister(&sbp2_driver.driver); >> - destroy_workqueue(sbp2_wq); > > Hmmm... from glancing the code, there doesn't seem to anything which > can guarantee sbp2_release_target/reconnect() are finished before > sbp2_cleanup() returns, so the code section might go away with code > still running. It seems like the right thing to do here would be > using alloc_workqueue(KBUILD_MODNAME, WQ_NON_REENTRANT, 0). Am I > missing something? There are indeed situations where the last module reference was already put down before the work is run for the last time. Thanks for the hint. What is preferable, an own workqueue instance whose destroy_workqueue() lets sbp2_cleanup wait for unfinished work, or module ref-counting like below? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . [PATCH] firewire: sbp2: hold a reference for workqueue jobs which can be run after sbp2_release. While SCSI core usually still holds a reference to the firewire-sbp2 module at that point, it might not do so anymore in some special cases where the scsi_device was dropped earlier. Reported-by: Tejun Heo <tj@kernel.org> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> --- drivers/firewire/sbp2.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) Index: b/drivers/firewire/sbp2.c =================================================================== --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -821,8 +821,9 @@ static void sbp2_release_target(struct k fw_notify("released %s, target %d:0:0\n", tgt->bus_id, shost->host_no); fw_unit_put(tgt->unit); - scsi_host_put(shost); fw_device_put(device); + scsi_host_put(shost); + module_put(THIS_MODULE); } static void sbp2_target_get(struct sbp2_target *tgt) @@ -1139,13 +1140,17 @@ static int sbp2_probe(struct device *dev struct Scsi_Host *shost; u32 model, firmware_revision; + /* Take a reference for late workqueue jobs. */ + if (!try_module_get(THIS_MODULE)) + return -ECANCELED; + if (dma_get_max_seg_size(device->card->device) > SBP2_MAX_SEG_SIZE) BUG_ON(dma_set_max_seg_size(device->card->device, SBP2_MAX_SEG_SIZE)); shost = scsi_host_alloc(&scsi_driver_template, sizeof(*tgt)); if (shost == NULL) - return -ENOMEM; + goto fail; tgt = (struct sbp2_target *)shost->hostdata; dev_set_drvdata(&unit->device, tgt); @@ -1200,6 +1205,8 @@ static int sbp2_probe(struct device *dev fail_shost_put: scsi_host_put(shost); + fail: + module_put(THIS_MODULE); return -ENOMEM; } -- Stefan Richter -=====-==-=- =-=- -=-== http://arcgraph.de/sr/ ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown 2010-10-11 21:27 ` Stefan Richter @ 2010-10-11 21:39 ` Stefan Richter 2010-10-12 13:55 ` Tejun Heo 2010-10-12 13:50 ` Tejun Heo 1 sibling, 1 reply; 17+ messages in thread From: Stefan Richter @ 2010-10-11 21:39 UTC (permalink / raw) To: Tejun Heo; +Cc: linux1394-devel, linux-kernel Stefan Richter wrote: > There are indeed situations where the last module reference was already > put down before the work is run for the last time. Thanks for the hint. > > What is preferable, an own workqueue instance whose destroy_workqueue() > lets sbp2_cleanup wait for unfinished work, or module ref-counting like > below? Anoher thing: Somebody might have swap space on a FireWire disk. Yet the system workqueues that firewire-core and (perhaps) firewire-sbp2 are using are created without WQ_RESCUER. Does this --- fringe use case as it might be --- call for private workqueues in firewire-core (for fw_device.work) and firewire-sbp2 (for sbp2_logical_unit.work)? Besides the less interesting cases of device discovery and shutdown, both of these works are also involved in SBP reconnect which needs to be performed at each FireWire bus reset (which can happen anytime for a variety of reasons). -- Stefan Richter -=====-==-=- =-=- -=-== http://arcgraph.de/sr/ ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown 2010-10-11 21:39 ` Stefan Richter @ 2010-10-12 13:55 ` Tejun Heo 2010-10-12 16:15 ` Stefan Richter 0 siblings, 1 reply; 17+ messages in thread From: Tejun Heo @ 2010-10-12 13:55 UTC (permalink / raw) To: Stefan Richter; +Cc: linux1394-devel, linux-kernel Hello, On 10/11/2010 11:39 PM, Stefan Richter wrote: > Stefan Richter wrote: >> There are indeed situations where the last module reference was already >> put down before the work is run for the last time. Thanks for the hint. >> >> What is preferable, an own workqueue instance whose destroy_workqueue() >> lets sbp2_cleanup wait for unfinished work, or module ref-counting like >> below? > > Anoher thing: Somebody might have swap space on a FireWire disk. It doesn't have to be swap. Having a rw filesystem mounted is enough to be in the memory reclaim path. > Yet the system workqueues that firewire-core and (perhaps) > firewire-sbp2 are using are created without WQ_RESCUER. > > Does this --- fringe use case as it might be --- call for private > workqueues in firewire-core (for fw_device.work) and firewire-sbp2 (for > sbp2_logical_unit.work)? > > Besides the less interesting cases of device discovery and shutdown, > both of these works are also involved in SBP reconnect which needs to be > performed at each FireWire bus reset (which can happen anytime for a > variety of reasons). Yes, it would definitely be better to put them in a workqueue with WQ_RESCUER (or the new WQ_MEM_RECLAIM). Thanks. -- tejun ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown 2010-10-12 13:55 ` Tejun Heo @ 2010-10-12 16:15 ` Stefan Richter 2010-10-12 16:46 ` Tejun Heo 0 siblings, 1 reply; 17+ messages in thread From: Stefan Richter @ 2010-10-12 16:15 UTC (permalink / raw) To: Tejun Heo; +Cc: linux1394-devel, linux-kernel Tejun Hejo wrote: > It doesn't have to be swap. Having a rw filesystem mounted is enough > to be in the memory reclaim path. Oh, alright. ... > Yes, it would definitely be better to put them in a workqueue with > WQ_RESCUER (or the new WQ_MEM_RECLAIM). A pro pos WQ_MEM_RECLAIM, is wq.git#for-next stable history which I can pull into a topic branch at linux1394-2.6.git? (Or I wait with this stuff until after .37-rc1.) -- Stefan Richter -=====-==-=- =-=- -==-- http://arcgraph.de/sr/ ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown 2010-10-12 16:15 ` Stefan Richter @ 2010-10-12 16:46 ` Tejun Heo 0 siblings, 0 replies; 17+ messages in thread From: Tejun Heo @ 2010-10-12 16:46 UTC (permalink / raw) To: Stefan Richter; +Cc: linux1394-devel, linux-kernel Hello, On 10/12/2010 06:15 PM, Stefan Richter wrote: > Tejun Hejo wrote: >> It doesn't have to be swap. Having a rw filesystem mounted is enough >> to be in the memory reclaim path. > > Oh, alright. > > ... >> Yes, it would definitely be better to put them in a workqueue with >> WQ_RESCUER (or the new WQ_MEM_RECLAIM). > > A pro pos WQ_MEM_RECLAIM, is wq.git#for-next stable history which I can pull > into a topic branch at linux1394-2.6.git? (Or I wait with this stuff until > after .37-rc1.) For now using WQ_RESCUER should do. We can update it to WQ_MEM_RECLAIM after the trees are merged (both flags have the same meaning now so nothing would break). Thanks. -- tejun ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown 2010-10-11 21:27 ` Stefan Richter 2010-10-11 21:39 ` Stefan Richter @ 2010-10-12 13:50 ` Tejun Heo 1 sibling, 0 replies; 17+ messages in thread From: Tejun Heo @ 2010-10-12 13:50 UTC (permalink / raw) To: Stefan Richter; +Cc: linux1394-devel, linux-kernel Hello, On 10/11/2010 11:27 PM, Stefan Richter wrote: >> Hmmm... from glancing the code, there doesn't seem to anything which >> can guarantee sbp2_release_target/reconnect() are finished before >> sbp2_cleanup() returns, so the code section might go away with code >> still running. It seems like the right thing to do here would be >> using alloc_workqueue(KBUILD_MODNAME, WQ_NON_REENTRANT, 0). Am I >> missing something? > > There are indeed situations where the last module reference was already > put down before the work is run for the last time. Thanks for the hint. > > What is preferable, an own workqueue instance whose destroy_workqueue() > lets sbp2_cleanup wait for unfinished work, or module ref-counting like > below? The best would be flushing the specific works but that isn't possible when works are used to do the final put. I would go for using a separate workqueue. With cmwq, each workqueue is much cheaper than before anyway. Thanks. -- tejun ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH unfinished update] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown 2010-10-10 14:57 ` [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown Stefan Richter 2010-10-11 13:43 ` Tejun Heo @ 2010-10-12 21:39 ` Stefan Richter 2010-10-12 22:25 ` Stefan Richter 1 sibling, 1 reply; 17+ messages in thread From: Stefan Richter @ 2010-10-12 21:39 UTC (permalink / raw) To: linux1394-devel; +Cc: linux-kernel, Tejun Heo So I changed the patch to the simple one below, but suddenly my INIC-2430 device has trouble with inquiry in parallel to its two LUNs: Oct 12 23:23:50 stein kernel: scsi22 : SBP-2 IEEE-1394 Oct 12 23:23:50 stein kernel: firewire_sbp2: Workarounds for fw7.0: 0x2 (firmware_revision 0x000241, model_id 0x000000) Oct 12 23:23:50 stein kernel: scsi23 : SBP-2 IEEE-1394 Oct 12 23:23:50 stein kernel: firewire_sbp2: Workarounds for fw7.1: 0x2 (firmware_revision 0x000241, model_id 0x000000) Oct 12 23:23:50 stein kernel: firewire_core: created device fw7: GUID 00027a0e440020c2, S800 Oct 12 23:23:50 stein kernel: firewire_sbp2: fw7.0: logged in to LUN 0000 (0 retries) Oct 12 23:23:50 stein kernel: firewire_sbp2: fw7.1: logged in to LUN 0001 (0 retries) Oct 12 23:23:52 stein kernel: scsi 23:0:0:1: CD-ROM TEAC DV-516GC XT11 PQ: 0 ANSI: 0 Oct 12 23:23:52 stein kernel: sr1: scsi3-mmc drive: 48x/48x cd/rw xa/form2 cdda tray Oct 12 23:23:52 stein kernel: sr 23:0:0:1: Attached scsi CD-ROM sr1 Oct 12 23:23:52 stein kernel: sr 23:0:0:1: Attached scsi generic sg6 type 5 Oct 12 23:23:52 stein kernel: firewire_sbp2: fw7.0: orb reply timed out, rcode=0x11 When I then force a bus reset by hardware or software, the device comes to its senses: Oct 12 23:24:38 stein kernel: firewire_sbp2: fw7.0: logged in to LUN 0000 (0 retries) Oct 12 23:24:38 stein kernel: firewire_sbp2: fw7.1: reconnected to LUN 0001 (0 retries) Oct 12 23:24:38 stein kernel: scsi 22:0:0:0: CD-ROM TEAC DV-516GC XT11 PQ: 0 ANSI: 0 Oct 12 23:24:38 stein kernel: sr2: scsi3-mmc drive: 48x/48x cd/rw xa/form2 cdda tray Oct 12 23:24:38 stein kernel: sr 22:0:0:0: Attached scsi CD-ROM sr2 Oct 12 23:24:38 stein kernel: sr 22:0:0:0: Attached scsi generic sg7 type 5 The initial Inquiry(?) timeout happens not always but quite often. It did not happen when I tested the earlier version of the patch in which I used system_nrt_wq. Maybe I need ordered per-target workqueues. Not Signed-off-by me yet. Tejun, can a workqueue job call destroy_workqueue on its own queue? --- drivers/firewire/sbp2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) Index: b/drivers/firewire/sbp2.c =================================================================== --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -1656,7 +1656,8 @@ MODULE_ALIAS("sbp2"); static int __init sbp2_init(void) { - sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME); + sbp2_wq = alloc_workqueue(KBUILD_MODNAME, + WQ_NON_REENTRANT | WQ_RESCUER, 0); if (!sbp2_wq) return -ENOMEM; -- Stefan Richter -=====-==-=- =-=- -==-- http://arcgraph.de/sr/ ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH unfinished update] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown 2010-10-12 21:39 ` [PATCH unfinished update] " Stefan Richter @ 2010-10-12 22:25 ` Stefan Richter 2010-10-12 23:09 ` Stefan Richter 0 siblings, 1 reply; 17+ messages in thread From: Stefan Richter @ 2010-10-12 22:25 UTC (permalink / raw) To: linux1394-devel; +Cc: linux-kernel, Tejun Heo > So I changed the patch to the simple one below, but suddenly my > INIC-2430 device has trouble with inquiry in parallel to its two LUNs: The following modification fixes this mostly, i.e. always when the first Inquiry attempt to one LUN fails but succeeds on the other. But I had one occasion just now at which both failed; then that reschedule does simply lead into the same situation until retry limit. > Maybe I need ordered per-target workqueues. No, I actually need per-node ordering. This device, like my other one and apparently most ones on the market actually keep their SCSI logical units in separate FireWire units. Currently firewire-sbp2 is not aware that fw_unit instances reside on the same node. This is going to be tougher than I hoped. Maybe I need a driver-global Inquiry mutex. Or move the __scsi_add_device() out of sbp2_login() into another work which is scheduled to a "single-threaded" workqueue. --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -982,6 +982,8 @@ static void sbp2_login(struct work_struc * lu->work already. Reset the work from reconnect to login. */ PREPARE_DELAYED_WORK(&lu->work, sbp2_login); + if (lu->retries++ < 5) + sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); out: sbp2_target_put(tgt); } @@ -1656,7 +1658,8 @@ MODULE_ALIAS("sbp2"); static int __init sbp2_init(void) { - sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME); + sbp2_wq = alloc_workqueue(KBUILD_MODNAME, + WQ_NON_REENTRANT | WQ_RESCUER, 0); if (!sbp2_wq) return -ENOMEM; -- Stefan Richter -=====-==-=- =-=- -==-= http://arcgraph.de/sr/ ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH unfinished update] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown 2010-10-12 22:25 ` Stefan Richter @ 2010-10-12 23:09 ` Stefan Richter 2010-10-13 9:45 ` Tejun Heo 0 siblings, 1 reply; 17+ messages in thread From: Stefan Richter @ 2010-10-12 23:09 UTC (permalink / raw) To: linux1394-devel; +Cc: linux-kernel, Tejun Heo Stefan Richter wrote: >> Maybe I need ordered per-target workqueues. > > No, I actually need per-node ordering. This device, like my other one > and apparently most ones on the market actually keep their SCSI logical > units in separate FireWire units. Currently firewire-sbp2 is not aware > that fw_unit instances reside on the same node. > > This is going to be tougher than I hoped. Maybe I need a driver-global > Inquiry mutex. Or move the __scsi_add_device() out of sbp2_login() into > another work which is scheduled to a "single-threaded" workqueue. More extensive change but probably with simpler end result: Let sbp2_probe and sbp2_update perform login/scsi_add_device/reconnect directly. sbp2_probe and sbp2_update are serialized per node, but (since 2.6.36 with cmwq) parallelized across nodes. -- Stefan Richter -=====-==-=- =-=- -==-= http://arcgraph.de/sr/ ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH unfinished update] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown 2010-10-12 23:09 ` Stefan Richter @ 2010-10-13 9:45 ` Tejun Heo 0 siblings, 0 replies; 17+ messages in thread From: Tejun Heo @ 2010-10-13 9:45 UTC (permalink / raw) To: Stefan Richter; +Cc: linux1394-devel, linux-kernel Hello, On 10/13/2010 01:09 AM, Stefan Richter wrote: > More extensive change but probably with simpler end result: Let > sbp2_probe and sbp2_update perform login/scsi_add_device/reconnect > directly. sbp2_probe and sbp2_update are serialized per node, but > (since 2.6.36 with cmwq) parallelized across nodes. I don't know much about firewire details but just in case it helps. libata does the ATA part of probing in parallel using the async mechanism (which is a wrapper around workqueue now) and executes the SCSI probing in a serialized context. If SCSI parallel probing is causing the problem, maybe firewire can do similar thing? The difference between using async and workqueue directly is only in how things can be ordered. There are cases where parallelizing probe is easier with async but one way or the other it shouldn't matter too much. Thanks. -- tejun ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] firewire: core: use non-reentrant workqueue where necessary 2010-10-10 14:55 [PATCH] firewire: core: use non-reentrant workqueue where necessary Stefan Richter 2010-10-10 14:57 ` [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown Stefan Richter @ 2010-10-11 13:29 ` Tejun Heo 2010-10-11 19:05 ` Stefan Richter 2010-10-12 21:29 ` [PATCH update] firewire: core: use non-reentrant workqueue with rescuer Stefan Richter 2 siblings, 1 reply; 17+ messages in thread From: Tejun Heo @ 2010-10-11 13:29 UTC (permalink / raw) To: Stefan Richter; +Cc: linux1394-devel, linux-kernel Hello, Stefan. On 10/10/2010 04:55 PM, Stefan Richter wrote: ... > 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. Awesome, thanks a lot for doing this. BTW, I'm in the process of hunting down all flush_scheduled_work() users and plan to remove workqueue flushing capability from all system workqueues. > Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> For the workqueue part, Acked-by: Tejun Heo <tj@kernel.org> -- tejun ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] firewire: core: use non-reentrant workqueue where necessary 2010-10-11 13:29 ` [PATCH] firewire: core: use non-reentrant workqueue where necessary Tejun Heo @ 2010-10-11 19:05 ` Stefan Richter 0 siblings, 0 replies; 17+ messages in thread From: Stefan Richter @ 2010-10-11 19:05 UTC (permalink / raw) To: Tejun Heo; +Cc: linux1394-devel, linux-kernel Tejun Heo wrote: > For the workqueue part, > > Acked-by: Tejun Heo <tj@kernel.org> Thanks for looking at it. (And for pointing out the reentrance issue with the original system workqueue earlier during the cmwq postings.) -- Stefan Richter -=====-==-=- =-=- -=-== http://arcgraph.de/sr/ ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH update] firewire: core: use non-reentrant workqueue with rescuer 2010-10-10 14:55 [PATCH] firewire: core: use non-reentrant workqueue where necessary Stefan Richter 2010-10-10 14:57 ` [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown Stefan Richter 2010-10-11 13:29 ` [PATCH] firewire: core: use non-reentrant workqueue where necessary Tejun Heo @ 2010-10-12 21:29 ` Stefan Richter 2010-10-13 9:47 ` Tejun Heo 2 siblings, 1 reply; 17+ messages in thread From: Stefan Richter @ 2010-10-12 21:29 UTC (permalink / raw) To: linux1394-devel; +Cc: linux-kernel, Tejun Heo 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 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 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 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 fw_card.br_work instances should not, and instances of the others must not, be executed in parallel by multiple CPUs -- but were not protected against that. Hence allocated a non-reentrant workqueue for them. fw_device.work may be used in the memory reclaim path in case of SBP-2 device updates. Hence we need a workqueue with rescuer and cannot use system_nrt_wq. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> --- drivers/firewire/core-card.c | 6 +++--- drivers/firewire/core-cdev.c | 2 +- drivers/firewire/core-device.c | 30 ++++++++++++++++++---------- drivers/firewire/core-transaction.c | 12 ++++++++++- drivers/firewire/core.h | 2 ++ 5 files changed, 36 insertions(+), 16 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(fw_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(fw_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(fw_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,14 @@ struct fw_device *fw_device_get_by_devt( return device; } +struct workqueue_struct *fw_wq; + +static void fw_schedule_device_work(struct fw_device *device, + unsigned long delay) +{ + queue_delayed_work(fw_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 +757,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 +869,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 +960,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 +1025,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 +1104,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 +1137,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 +1164,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 +1217,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 +1232,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 +1247,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 +1272,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; Index: b/drivers/firewire/core-transaction.c =================================================================== --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -36,6 +36,7 @@ #include <linux/string.h> #include <linux/timer.h> #include <linux/types.h> +#include <linux/workqueue.h> #include <asm/byteorder.h> @@ -1192,13 +1193,21 @@ static int __init fw_core_init(void) { int ret; + fw_wq = alloc_workqueue(KBUILD_MODNAME, + WQ_NON_REENTRANT | WQ_RESCUER, 0); + if (!fw_wq) + return -ENOMEM; + ret = bus_register(&fw_bus_type); - if (ret < 0) + if (ret < 0) { + destroy_workqueue(fw_wq); return ret; + } fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); if (fw_cdev_major < 0) { bus_unregister(&fw_bus_type); + destroy_workqueue(fw_wq); return fw_cdev_major; } @@ -1214,6 +1223,7 @@ static void __exit fw_core_cleanup(void) { unregister_chrdev(fw_cdev_major, "firewire"); bus_unregister(&fw_bus_type); + destroy_workqueue(fw_wq); idr_destroy(&fw_device_idr); } Index: b/drivers/firewire/core.h =================================================================== --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -138,6 +138,8 @@ void fw_cdev_handle_phy_packet(struct fw extern struct rw_semaphore fw_device_rwsem; extern struct idr fw_device_idr; extern int fw_cdev_major; +struct workqueue_struct; +extern struct workqueue_struct *fw_wq; struct fw_device *fw_device_get_by_devt(dev_t devt); int fw_device_set_broadcast_channel(struct device *dev, void *gen); -- Stefan Richter -=====-==-=- =-=- -==-- http://arcgraph.de/sr/ ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH update] firewire: core: use non-reentrant workqueue with rescuer 2010-10-12 21:29 ` [PATCH update] firewire: core: use non-reentrant workqueue with rescuer Stefan Richter @ 2010-10-13 9:47 ` Tejun Heo 0 siblings, 0 replies; 17+ messages in thread From: Tejun Heo @ 2010-10-13 9:47 UTC (permalink / raw) To: Stefan Richter; +Cc: linux1394-devel, linux-kernel Hello, On 10/12/2010 11:29 PM, Stefan Richter wrote: ... > fw_card.br_work instances should not, and instances of the others must > not, be executed in parallel by multiple CPUs -- but were not protected > against that. Hence allocated a non-reentrant workqueue for them. > > fw_device.work may be used in the memory reclaim path in case of SBP-2 > device updates. Hence we need a workqueue with rescuer and cannot use > system_nrt_wq. > > Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Looks good to me. Reviewed-by: Tejun Heo <tj@kernel.org> Thanks. -- tejun ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2010-10-13 9:47 UTC | newest] Thread overview: 17+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-10-10 14:55 [PATCH] firewire: core: use non-reentrant workqueue where necessary Stefan Richter 2010-10-10 14:57 ` [PATCH] firewire: sbp2: parallelize login/inquiry, reconnect, and shutdown Stefan Richter 2010-10-11 13:43 ` Tejun Heo 2010-10-11 21:27 ` Stefan Richter 2010-10-11 21:39 ` Stefan Richter 2010-10-12 13:55 ` Tejun Heo 2010-10-12 16:15 ` Stefan Richter 2010-10-12 16:46 ` Tejun Heo 2010-10-12 13:50 ` Tejun Heo 2010-10-12 21:39 ` [PATCH unfinished update] " Stefan Richter 2010-10-12 22:25 ` Stefan Richter 2010-10-12 23:09 ` Stefan Richter 2010-10-13 9:45 ` Tejun Heo 2010-10-11 13:29 ` [PATCH] firewire: core: use non-reentrant workqueue where necessary Tejun Heo 2010-10-11 19:05 ` Stefan Richter 2010-10-12 21:29 ` [PATCH update] firewire: core: use non-reentrant workqueue with rescuer Stefan Richter 2010-10-13 9:47 ` Tejun Heo
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox