aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi
diff options
context:
space:
mode:
authorJames Bottomley2011-03-10 17:13:18 -0600
committerJames Bottomley2011-03-14 18:46:25 -0500
commita82058a730c2bd01c43beb8a4847526a2998cc1a (patch)
tree92608d5ecc6e70976fb320fe0c48074b5e0e5a01 /drivers/scsi
parent941b1cdae83039c99fc5c1884a98d2afd39760e5 (diff)
[SCSI] libsas: fix ata list corruption issue
I think this stems from a misunderstanding of how the ata error handler works. ata_scsi_cmd_error_handler() gets called with a passed in list of commands to handle. However, that list may still not be empty when it exits. The command ata_scsi_port_error_handler() must be called (which takes no list) before the list will be completely emptied. This bites the sas error handler because the two are called from different functions and the original list has gone out of scope before ata_scsi_port_error_handler() is called. leading to some commands dangling on bare stack, which is a potential memory corruption issue. Fix this by manually deleting all outstanding commands from the on-stack list before it goes out of scope. Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/libsas/sas_ata.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 16c5094bc86c..3356bf36cd98 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -802,6 +802,19 @@ int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
if (!list_empty(&sata_q)) {
ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata cmd error handler\n");
ata_scsi_cmd_error_handler(shost, ap, &sata_q);
+ /*
+ * ata's error handler may leave the cmd on the list
+ * so make sure they don't remain on a stack list
+ * about to go out of scope.
+ *
+ * This looks strange, since the commands are
+ * now part of no list, but the next error
+ * action will be ata_port_error_handler()
+ * which takes no list and sweeps them up
+ * anyway from the ata tag array.
+ */
+ while (!list_empty(&sata_q))
+ list_del_init(sata_q.next);
}
} while (ap);