diff options
author | Darrick J. Wong <djwong@us.ibm.com> | 2007-01-11 17:15:00 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-01-13 17:13:38 -0500 |
commit | 6d4dcd4dae25c48e8932326aaedfe560d7f2c7bb (patch) | |
tree | 4ab6566de836ff50931ee7487d7e7c7ad6d11b39 /drivers/scsi | |
parent | acbf167d4ad8c27f9743a4b539d51ae9535bf21c (diff) |
[SCSI] libsas: Reset timer on taskless scsi_cmnds in sas_scsi_timed_out
Every so often, a scsi_cmnd will time out, and the libsas timeout handler
will discover that the scsi_cmnd does not have a sas_task attached to it.
This can happen in two cases: (1) the scsi_cmnd actually made it through
libsas to the HBA and is now going through scsi_done, or (2) the
scsi_cmnd has been held up (host lock, slab alloc, etc) and libsas has
not yet attached a sas_task. In both cases, it is safe to ask SCSI for
more time to process the command via EH_RESET_TIMER; we cannot blindly
return EH_HANDLED because if (2) happens, we could end up calling
scsi_done while another CPU is heading towards sas_queuecommand, which
causes slab corruption when sas_task_done updates the freed scsi_cmnd.
Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 7774eb3628ad..3f647c695da5 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -524,9 +524,13 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) | |||
524 | unsigned long flags; | 524 | unsigned long flags; |
525 | 525 | ||
526 | if (!task) { | 526 | if (!task) { |
527 | SAS_DPRINTK("command 0x%p, task 0x%p, gone: EH_HANDLED\n", | 527 | cmd->timeout_per_command /= 2; |
528 | cmd, task); | 528 | SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n", |
529 | return EH_HANDLED; | 529 | cmd, task, (cmd->timeout_per_command ? |
530 | "EH_RESET_TIMER" : "EH_NOT_HANDLED")); | ||
531 | if (!cmd->timeout_per_command) | ||
532 | return EH_NOT_HANDLED; | ||
533 | return EH_RESET_TIMER; | ||
530 | } | 534 | } |
531 | 535 | ||
532 | spin_lock_irqsave(&task->task_state_lock, flags); | 536 | spin_lock_irqsave(&task->task_state_lock, flags); |