Commit df8ec249 authored by Stefan Richter's avatar Stefan Richter

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: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
Signed-off-by: default avatarKristian Høgsberg <krh@redhat.com>
parent 2df222b8
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/stringify.h> #include <linux/stringify.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/workqueue.h>
#include <scsi/scsi.h> #include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h> #include <scsi/scsi_cmnd.h>
...@@ -625,6 +626,8 @@ static void sbp2_release_target(struct kref *kref) ...@@ -625,6 +626,8 @@ static void sbp2_release_target(struct kref *kref)
scsi_host_put(shost); scsi_host_put(shost);
} }
static struct workqueue_struct *sbp2_wq;
static void sbp2_reconnect(struct work_struct *work); static void sbp2_reconnect(struct work_struct *work);
static void sbp2_login(struct work_struct *work) static void sbp2_login(struct work_struct *work)
...@@ -647,7 +650,8 @@ 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, if (sbp2_send_management_orb(lu, node_id, generation,
SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) { SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) {
if (lu->retries++ < 5) { 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 { } else {
fw_error("failed to login to %s LUN %04x\n", fw_error("failed to login to %s LUN %04x\n",
unit->device.bus_id, lu->lun); unit->device.bus_id, lu->lun);
...@@ -866,7 +870,7 @@ static int sbp2_probe(struct device *dev) ...@@ -866,7 +870,7 @@ static int sbp2_probe(struct device *dev)
* work. * work.
*/ */
list_for_each_entry(lu, &tgt->lu_list, link) 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); kref_get(&tgt->kref);
return 0; return 0;
...@@ -910,7 +914,7 @@ static void sbp2_reconnect(struct work_struct *work) ...@@ -910,7 +914,7 @@ static void sbp2_reconnect(struct work_struct *work)
lu->retries = 0; lu->retries = 0;
PREPARE_DELAYED_WORK(&lu->work, sbp2_login); 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; return;
} }
...@@ -940,7 +944,7 @@ static void sbp2_update(struct fw_unit *unit) ...@@ -940,7 +944,7 @@ static void sbp2_update(struct fw_unit *unit)
*/ */
list_for_each_entry(lu, &tgt->lu_list, link) { list_for_each_entry(lu, &tgt->lu_list, link) {
lu->retries = 0; lu->retries = 0;
if (schedule_delayed_work(&lu->work, 0)) if (queue_delayed_work(sbp2_wq, &lu->work, 0))
kref_get(&tgt->kref); kref_get(&tgt->kref);
} }
} }
...@@ -1335,12 +1339,17 @@ MODULE_ALIAS("sbp2"); ...@@ -1335,12 +1339,17 @@ MODULE_ALIAS("sbp2");
static int __init sbp2_init(void) static int __init sbp2_init(void)
{ {
sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME);
if (!sbp2_wq)
return -ENOMEM;
return driver_register(&sbp2_driver.driver); return driver_register(&sbp2_driver.driver);
} }
static void __exit sbp2_cleanup(void) static void __exit sbp2_cleanup(void)
{ {
driver_unregister(&sbp2_driver.driver); driver_unregister(&sbp2_driver.driver);
destroy_workqueue(sbp2_wq);
} }
module_init(sbp2_init); module_init(sbp2_init);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment