diff options
author | Christoph Hellwig <hch@infradead.org> | 2011-10-17 13:56:53 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-10-24 03:21:52 +0000 |
commit | 35e0e757537b9239172e35db773dd062727fd612 (patch) | |
tree | 3a54e1e426f1a962219325eac474b715a4699924 /drivers/target/target_core_tmr.c | |
parent | 59aaad1ec44d9a77c32b873b001f31c5af47fcc7 (diff) |
target: use a workqueue for I/O completions
Instead of abusing the target processing thread for offloading I/O
completion in the backends to user context add a new workqueue. This means
completions can be processed as fast as available CPU time allows it,
including in parallel with other completions and more importantly I/O
submission or QUEUE FULL retries. This should give much better performance
especially on loaded systems.
As a fallout we can merge all the completed states into a single
one.
On the downside this change complicates lun reset handling a bit by
requiring us to cancel a work item only for those states that have it
initialized. The alternative would be to either always initialize the work
item to a dummy handler, or always use the same handler and do a switch on
the state. The long term solution will be a flag that says that the command
has an initialized work item, but that's only going to be useful once we
have more users.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/target_core_tmr.c')
-rw-r--r-- | drivers/target/target_core_tmr.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 532ce317406..570b144a1ed 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -255,6 +255,16 @@ static void core_tmr_drain_task_list( atomic_read(&cmd->t_transport_stop), atomic_read(&cmd->t_transport_sent)); + /* + * If the command may be queued onto a workqueue cancel it now. + * + * This is equivalent to removal from the execute queue in the + * loop above, but we do it down here given that + * cancel_work_sync may block. + */ + if (cmd->t_state == TRANSPORT_COMPLETE) + cancel_work_sync(&cmd->work); + spin_lock_irqsave(&cmd->t_state_lock, flags); target_stop_task(task, &flags); |