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 | |
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')
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 84 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 44 |
2 files changed, 75 insertions, 53 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 5cb0a2ae5924..903bb441b9f9 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c | |||
@@ -100,15 +100,31 @@ static void sas_ata_task_done(struct sas_task *task) | |||
100 | enum ata_completion_errors ac; | 100 | enum ata_completion_errors ac; |
101 | unsigned long flags; | 101 | unsigned long flags; |
102 | struct ata_link *link; | 102 | struct ata_link *link; |
103 | struct ata_port *ap; | ||
103 | 104 | ||
104 | if (!qc) | 105 | if (!qc) |
105 | goto qc_already_gone; | 106 | goto qc_already_gone; |
106 | 107 | ||
107 | dev = qc->ap->private_data; | 108 | ap = qc->ap; |
109 | dev = ap->private_data; | ||
108 | sas_ha = dev->port->ha; | 110 | sas_ha = dev->port->ha; |
109 | link = &dev->sata_dev.ap->link; | 111 | link = &ap->link; |
112 | |||
113 | spin_lock_irqsave(ap->lock, flags); | ||
114 | /* check if we lost the race with libata/sas_ata_post_internal() */ | ||
115 | if (unlikely(ap->pflags & ATA_PFLAG_FROZEN)) { | ||
116 | spin_unlock_irqrestore(ap->lock, flags); | ||
117 | if (qc->scsicmd) | ||
118 | goto qc_already_gone; | ||
119 | else { | ||
120 | /* if eh is not involved and the port is frozen then the | ||
121 | * ata internal abort process has taken responsibility | ||
122 | * for this sas_task | ||
123 | */ | ||
124 | return; | ||
125 | } | ||
126 | } | ||
110 | 127 | ||
111 | spin_lock_irqsave(dev->sata_dev.ap->lock, flags); | ||
112 | if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD || | 128 | if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD || |
113 | ((stat->stat == SAM_STAT_CHECK_CONDITION && | 129 | ((stat->stat == SAM_STAT_CHECK_CONDITION && |
114 | dev->sata_dev.command_set == ATAPI_COMMAND_SET))) { | 130 | dev->sata_dev.command_set == ATAPI_COMMAND_SET))) { |
@@ -143,7 +159,7 @@ static void sas_ata_task_done(struct sas_task *task) | |||
143 | if (qc->scsicmd) | 159 | if (qc->scsicmd) |
144 | ASSIGN_SAS_TASK(qc->scsicmd, NULL); | 160 | ASSIGN_SAS_TASK(qc->scsicmd, NULL); |
145 | ata_qc_complete(qc); | 161 | ata_qc_complete(qc); |
146 | spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags); | 162 | spin_unlock_irqrestore(ap->lock, flags); |
147 | 163 | ||
148 | qc_already_gone: | 164 | qc_already_gone: |
149 | list_del_init(&task->list); | 165 | list_del_init(&task->list); |
@@ -325,6 +341,54 @@ static int sas_ata_soft_reset(struct ata_link *link, unsigned int *class, | |||
325 | return ret; | 341 | return ret; |
326 | } | 342 | } |
327 | 343 | ||
344 | /* | ||
345 | * notify the lldd to forget the sas_task for this internal ata command | ||
346 | * that bypasses scsi-eh | ||
347 | */ | ||
348 | static void sas_ata_internal_abort(struct sas_task *task) | ||
349 | { | ||
350 | struct sas_internal *si = | ||
351 | to_sas_internal(task->dev->port->ha->core.shost->transportt); | ||
352 | unsigned long flags; | ||
353 | int res; | ||
354 | |||
355 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
356 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED || | ||
357 | task->task_state_flags & SAS_TASK_STATE_DONE) { | ||
358 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
359 | SAS_DPRINTK("%s: Task %p already finished.\n", __func__, | ||
360 | task); | ||
361 | goto out; | ||
362 | } | ||
363 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | ||
364 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
365 | |||
366 | res = si->dft->lldd_abort_task(task); | ||
367 | |||
368 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
369 | if (task->task_state_flags & SAS_TASK_STATE_DONE || | ||
370 | res == TMF_RESP_FUNC_COMPLETE) { | ||
371 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
372 | goto out; | ||
373 | } | ||
374 | |||
375 | /* XXX we are not prepared to deal with ->lldd_abort_task() | ||
376 | * failures. TODO: lldds need to unconditionally forget about | ||
377 | * aborted ata tasks, otherwise we (likely) leak the sas task | ||
378 | * here | ||
379 | */ | ||
380 | SAS_DPRINTK("%s: Task %p leaked.\n", __func__, task); | ||
381 | |||
382 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) | ||
383 | task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; | ||
384 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
385 | |||
386 | return; | ||
387 | out: | ||
388 | list_del_init(&task->list); | ||
389 | sas_free_task(task); | ||
390 | } | ||
391 | |||
328 | static void sas_ata_post_internal(struct ata_queued_cmd *qc) | 392 | static void sas_ata_post_internal(struct ata_queued_cmd *qc) |
329 | { | 393 | { |
330 | if (qc->flags & ATA_QCFLAG_FAILED) | 394 | if (qc->flags & ATA_QCFLAG_FAILED) |
@@ -332,10 +396,12 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc) | |||
332 | 396 | ||
333 | if (qc->err_mask) { | 397 | if (qc->err_mask) { |
334 | /* | 398 | /* |
335 | * Find the sas_task and kill it. By this point, | 399 | * Find the sas_task and kill it. By this point, libata |
336 | * libata has decided to kill the qc, so we needn't | 400 | * has decided to kill the qc and has frozen the port. |
337 | * bother with sas_ata_task_done. But we still | 401 | * In this state sas_ata_task_done() will no longer free |
338 | * ought to abort the task. | 402 | * the sas_task, so we need to notify the lldd (via |
403 | * ->lldd_abort_task) that the task is dead and free it | ||
404 | * ourselves. | ||
339 | */ | 405 | */ |
340 | struct sas_task *task = qc->lldd_task; | 406 | struct sas_task *task = qc->lldd_task; |
341 | unsigned long flags; | 407 | unsigned long flags; |
@@ -348,7 +414,7 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc) | |||
348 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 414 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
349 | 415 | ||
350 | task->uldd_task = NULL; | 416 | task->uldd_task = NULL; |
351 | __sas_task_abort(task); | 417 | sas_ata_internal_abort(task); |
352 | } | 418 | } |
353 | } | 419 | } |
354 | } | 420 | } |
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); |