diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-08-12 06:51:18 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-10-16 18:00:04 -0400 |
commit | df8ec2490fed5dd23316bbb2c2e90e59e7d37126 (patch) | |
tree | 398b8a3e8ab2e1de31a17104b92981b9960c3e39 /drivers | |
parent | 2df222b8f8fe9e18c9c9fdfd46f60dad55f5ac14 (diff) |
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')
-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 @@ | |||
39 | #include <linux/string.h> | 39 | #include <linux/string.h> |
40 | #include <linux/stringify.h> | 40 | #include <linux/stringify.h> |
41 | #include <linux/timer.h> | 41 | #include <linux/timer.h> |
42 | #include <linux/workqueue.h> | ||
42 | 43 | ||
43 | #include <scsi/scsi.h> | 44 | #include <scsi/scsi.h> |
44 | #include <scsi/scsi_cmnd.h> | 45 | #include <scsi/scsi_cmnd.h> |
@@ -625,6 +626,8 @@ static void sbp2_release_target(struct kref *kref) | |||
625 | scsi_host_put(shost); | 626 | scsi_host_put(shost); |
626 | } | 627 | } |
627 | 628 | ||
629 | static struct workqueue_struct *sbp2_wq; | ||
630 | |||
628 | static void sbp2_reconnect(struct work_struct *work); | 631 | static void sbp2_reconnect(struct work_struct *work); |
629 | 632 | ||
630 | static void sbp2_login(struct work_struct *work) | 633 | static void sbp2_login(struct work_struct *work) |
@@ -647,7 +650,8 @@ static void sbp2_login(struct work_struct *work) | |||
647 | if (sbp2_send_management_orb(lu, node_id, generation, | 650 | if (sbp2_send_management_orb(lu, node_id, generation, |
648 | SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) { | 651 | SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) { |
649 | if (lu->retries++ < 5) { | 652 | if (lu->retries++ < 5) { |
650 | schedule_delayed_work(&lu->work, DIV_ROUND_UP(HZ, 5)); | 653 | queue_delayed_work(sbp2_wq, &lu->work, |
654 | DIV_ROUND_UP(HZ, 5)); | ||
651 | } else { | 655 | } else { |
652 | fw_error("failed to login to %s LUN %04x\n", | 656 | fw_error("failed to login to %s LUN %04x\n", |
653 | unit->device.bus_id, lu->lun); | 657 | unit->device.bus_id, lu->lun); |
@@ -866,7 +870,7 @@ static int sbp2_probe(struct device *dev) | |||
866 | * work. | 870 | * work. |
867 | */ | 871 | */ |
868 | list_for_each_entry(lu, &tgt->lu_list, link) | 872 | list_for_each_entry(lu, &tgt->lu_list, link) |
869 | if (schedule_delayed_work(&lu->work, 0)) | 873 | if (queue_delayed_work(sbp2_wq, &lu->work, 0)) |
870 | kref_get(&tgt->kref); | 874 | kref_get(&tgt->kref); |
871 | return 0; | 875 | return 0; |
872 | 876 | ||
@@ -910,7 +914,7 @@ static void sbp2_reconnect(struct work_struct *work) | |||
910 | lu->retries = 0; | 914 | lu->retries = 0; |
911 | PREPARE_DELAYED_WORK(&lu->work, sbp2_login); | 915 | PREPARE_DELAYED_WORK(&lu->work, sbp2_login); |
912 | } | 916 | } |
913 | schedule_delayed_work(&lu->work, DIV_ROUND_UP(HZ, 5)); | 917 | queue_delayed_work(sbp2_wq, &lu->work, DIV_ROUND_UP(HZ, 5)); |
914 | return; | 918 | return; |
915 | } | 919 | } |
916 | 920 | ||
@@ -940,7 +944,7 @@ static void sbp2_update(struct fw_unit *unit) | |||
940 | */ | 944 | */ |
941 | list_for_each_entry(lu, &tgt->lu_list, link) { | 945 | list_for_each_entry(lu, &tgt->lu_list, link) { |
942 | lu->retries = 0; | 946 | lu->retries = 0; |
943 | if (schedule_delayed_work(&lu->work, 0)) | 947 | if (queue_delayed_work(sbp2_wq, &lu->work, 0)) |
944 | kref_get(&tgt->kref); | 948 | kref_get(&tgt->kref); |
945 | } | 949 | } |
946 | } | 950 | } |
@@ -1335,12 +1339,17 @@ MODULE_ALIAS("sbp2"); | |||
1335 | 1339 | ||
1336 | static int __init sbp2_init(void) | 1340 | static int __init sbp2_init(void) |
1337 | { | 1341 | { |
1342 | sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME); | ||
1343 | if (!sbp2_wq) | ||
1344 | return -ENOMEM; | ||
1345 | |||
1338 | return driver_register(&sbp2_driver.driver); | 1346 | return driver_register(&sbp2_driver.driver); |
1339 | } | 1347 | } |
1340 | 1348 | ||
1341 | static void __exit sbp2_cleanup(void) | 1349 | static void __exit sbp2_cleanup(void) |
1342 | { | 1350 | { |
1343 | driver_unregister(&sbp2_driver.driver); | 1351 | driver_unregister(&sbp2_driver.driver); |
1352 | destroy_workqueue(sbp2_wq); | ||
1344 | } | 1353 | } |
1345 | 1354 | ||
1346 | module_init(sbp2_init); | 1355 | module_init(sbp2_init); |