summaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2007-08-12 12:51:18 +0200
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-10-17 00:00:04 +0200
commitdf8ec2490fed5dd23316bbb2c2e90e59e7d37126 (patch)
tree398b8a3e8ab2e1de31a17104b92981b9960c3e39 /drivers/firewire
parentfirewire: fw-sbp2: expose module parameter for workarounds (diff)
downloadlinux-df8ec2490fed5dd23316bbb2c2e90e59e7d37126.tar.xz
linux-df8ec2490fed5dd23316bbb2c2e90e59e7d37126.zip
firewire: fw-sbp2: use an own workqueue (fix system responsiveness)
Firewire-sbp2 did very uncooperative things in the kernel's shared workqueue: Sleeping until reception of management status from the target for up to 2 seconds, and performing SCSI inquiry and all of the setup of SCSI command set drivers via scsi_add_device. If there were transient or permanent error conditions, this caused long blockage of the kernel's events process, noticeable e.g. by blocked keyboard input. We now allocate a workqueue process exclusive to fw-sbp2. As a side effect, this also increases parallelism of fw-sbp2's login and reconnect work versus fw-core's device discovery and device update work which is performed in the shared workqueue. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/fw-sbp2.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index f96f19293dd1..5596df65c8ed 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -39,6 +39,7 @@
#include <linux/string.h>
#include <linux/stringify.h>
#include <linux/timer.h>
+#include <linux/workqueue.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -625,6 +626,8 @@ static void sbp2_release_target(struct kref *kref)
scsi_host_put(shost);
}
+static struct workqueue_struct *sbp2_wq;
+
static void sbp2_reconnect(struct work_struct *work);
static void sbp2_login(struct work_struct *work)
@@ -647,7 +650,8 @@ static void sbp2_login(struct work_struct *work)
if (sbp2_send_management_orb(lu, node_id, generation,
SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) {
if (lu->retries++ < 5) {
- schedule_delayed_work(&lu->work, DIV_ROUND_UP(HZ, 5));
+ queue_delayed_work(sbp2_wq, &lu->work,
+ DIV_ROUND_UP(HZ, 5));
} else {
fw_error("failed to login to %s LUN %04x\n",
unit->device.bus_id, lu->lun);
@@ -866,7 +870,7 @@ static int sbp2_probe(struct device *dev)
* work.
*/
list_for_each_entry(lu, &tgt->lu_list, link)
- if (schedule_delayed_work(&lu->work, 0))
+ if (queue_delayed_work(sbp2_wq, &lu->work, 0))
kref_get(&tgt->kref);
return 0;
@@ -910,7 +914,7 @@ static void sbp2_reconnect(struct work_struct *work)
lu->retries = 0;
PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
}
- schedule_delayed_work(&lu->work, DIV_ROUND_UP(HZ, 5));
+ queue_delayed_work(sbp2_wq, &lu->work, DIV_ROUND_UP(HZ, 5));
return;
}
@@ -940,7 +944,7 @@ static void sbp2_update(struct fw_unit *unit)
*/
list_for_each_entry(lu, &tgt->lu_list, link) {
lu->retries = 0;
- if (schedule_delayed_work(&lu->work, 0))
+ if (queue_delayed_work(sbp2_wq, &lu->work, 0))
kref_get(&tgt->kref);
}
}
@@ -1335,12 +1339,17 @@ 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);