Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8e436af9 authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik
Browse files

[PATCH] libata: fix ata_qc_issue() error handling



When ata_qc_issue() fails, the qc might have been dma mapped or not.
So, performing only ata_qc_free() results in dma map leak.  This patch
makes ata_qc_issue() mark dma map flags correctly on failure and calls
ata_qc_complete() after ata_qc_issue() fails.

Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent 77853bf2
Loading
Loading
Loading
Loading
+8 −10
Original line number Diff line number Diff line
@@ -1125,8 +1125,10 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
	qc->private_data = &wait;
	qc->complete_fn = ata_qc_complete_internal;

	if (ata_qc_issue(qc))
		goto issue_fail;
	if (ata_qc_issue(qc)) {
		qc->err_mask = AC_ERR_OTHER;
		ata_qc_complete(qc);
	}

	spin_unlock_irqrestore(&ap->host_set->lock, flags);

@@ -1155,11 +1157,6 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
	ata_qc_free(qc);

	return err_mask;

 issue_fail:
	ata_qc_free(qc);
	spin_unlock_irqrestore(&ap->host_set->lock, flags);
	return AC_ERR_OTHER;
}

/**
@@ -3687,10 +3684,10 @@ int ata_qc_issue(struct ata_queued_cmd *qc)
	if (ata_should_dma_map(qc)) {
		if (qc->flags & ATA_QCFLAG_SG) {
			if (ata_sg_setup(qc))
				goto err_out;
				goto sg_err;
		} else if (qc->flags & ATA_QCFLAG_SINGLE) {
			if (ata_sg_setup_one(qc))
				goto err_out;
				goto sg_err;
		}
	} else {
		qc->flags &= ~ATA_QCFLAG_DMAMAP;
@@ -3703,7 +3700,8 @@ int ata_qc_issue(struct ata_queued_cmd *qc)

	return ap->ops->qc_issue(qc);

err_out:
sg_err:
	qc->flags &= ~ATA_QCFLAG_DMAMAP;
	return -1;
}

+4 −2
Original line number Diff line number Diff line
@@ -1322,8 +1322,10 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
		goto early_finish;

	/* select device, send command to hardware */
	if (ata_qc_issue(qc))
		goto err_did;
	if (ata_qc_issue(qc)) {
		qc->err_mask |= AC_ERR_OTHER;
		ata_qc_complete(qc);
	}

	VPRINTK("EXIT\n");
	return;