diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-11-28 15:08:22 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-19 14:58:38 -0500 |
commit | 3dff5721e4f67e6231dfc419d30aaa7563bfffd4 (patch) | |
tree | 752102ef79f985f4d153b4791461404f67cdf467 /drivers/scsi/libsas/sas_scsi_host.c | |
parent | e500a34b0257def5b9ec07563afeeada1ead87bb (diff) |
[SCSI] libsas: close error handling vs sas_ata_task_done() race
Since sas_ata does not implement ->freeze(), completions for scmds and
internal commands can still arrive concurrent with
ata_scsi_cmd_error_handler() and sas_ata_post_internal() respectively.
By the time either of those is called libata has committed to completing
the qc, and the ATA_PFLAG_FROZEN flag tells sas_ata_task_done() it has
lost the race.
In the sas_ata_post_internal() case we take on the additional
responsibility of freeing the sas_task to close the race with
sas_ata_task_done() freeing the the task while sas_ata_post_internal()
is in the process of invoking ->lldd_abort_task().
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas/sas_scsi_host.c')
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 44 |
1 files changed, 0 insertions, 44 deletions
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 15533a17eb97..ba5876ccd29a 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -957,49 +957,6 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha) | |||
957 | } | 957 | } |
958 | 958 | ||
959 | /* | 959 | /* |
960 | * Call the LLDD task abort routine directly. This function is intended for | ||
961 | * use by upper layers that need to tell the LLDD to abort a task. | ||
962 | */ | ||
963 | int __sas_task_abort(struct sas_task *task) | ||
964 | { | ||
965 | struct sas_internal *si = | ||
966 | to_sas_internal(task->dev->port->ha->core.shost->transportt); | ||
967 | unsigned long flags; | ||
968 | int res; | ||
969 | |||
970 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
971 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED || | ||
972 | task->task_state_flags & SAS_TASK_STATE_DONE) { | ||
973 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
974 | SAS_DPRINTK("%s: Task %p already finished.\n", __func__, | ||
975 | task); | ||
976 | return 0; | ||
977 | } | ||
978 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | ||
979 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
980 | |||
981 | if (!si->dft->lldd_abort_task) | ||
982 | return -ENODEV; | ||
983 | |||
984 | res = si->dft->lldd_abort_task(task); | ||
985 | |||
986 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
987 | if ((task->task_state_flags & SAS_TASK_STATE_DONE) || | ||
988 | (res == TMF_RESP_FUNC_COMPLETE)) | ||
989 | { | ||
990 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
991 | task->task_done(task); | ||
992 | return 0; | ||
993 | } | ||
994 | |||
995 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) | ||
996 | task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; | ||
997 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
998 | |||
999 | return -EAGAIN; | ||
1000 | } | ||
1001 | |||
1002 | /* | ||
1003 | * Tell an upper layer that it needs to initiate an abort for a given task. | 960 | * Tell an upper layer that it needs to initiate an abort for a given task. |
1004 | * This should only ever be called by an LLDD. | 961 | * This should only ever be called by an LLDD. |
1005 | */ | 962 | */ |
@@ -1097,7 +1054,6 @@ EXPORT_SYMBOL_GPL(sas_slave_configure); | |||
1097 | EXPORT_SYMBOL_GPL(sas_change_queue_depth); | 1054 | EXPORT_SYMBOL_GPL(sas_change_queue_depth); |
1098 | EXPORT_SYMBOL_GPL(sas_change_queue_type); | 1055 | EXPORT_SYMBOL_GPL(sas_change_queue_type); |
1099 | EXPORT_SYMBOL_GPL(sas_bios_param); | 1056 | EXPORT_SYMBOL_GPL(sas_bios_param); |
1100 | EXPORT_SYMBOL_GPL(__sas_task_abort); | ||
1101 | EXPORT_SYMBOL_GPL(sas_task_abort); | 1057 | EXPORT_SYMBOL_GPL(sas_task_abort); |
1102 | EXPORT_SYMBOL_GPL(sas_phy_reset); | 1058 | EXPORT_SYMBOL_GPL(sas_phy_reset); |
1103 | EXPORT_SYMBOL_GPL(sas_phy_enable); | 1059 | EXPORT_SYMBOL_GPL(sas_phy_enable); |