diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-08-12 12:51:18 +0200 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-10-17 00:00:04 +0200 |
commit | df8ec2490fed5dd23316bbb2c2e90e59e7d37126 (patch) | |
tree | 398b8a3e8ab2e1de31a17104b92981b9960c3e39 /drivers/firewire/fw-sbp2.c | |
parent | 2df222b8f8fe9e18c9c9fdfd46f60dad55f5ac14 (diff) | |
download | lwn-df8ec2490fed5dd23316bbb2c2e90e59e7d37126.tar.gz lwn-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/fw-sbp2.c')
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 17 |
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); |