提交 1269a2ec 编写于 作者: J Jason Yan 提交者: Xie XiuQi

ata: fix a race condition when internal cmd time out

euler inclusion
category: bugfix
bugzilla: NA
CVE: NA

---------------------------

For internal cmds, we will unmap DMA memory associated with the cmd
before we abort the cmd. If DMA transferring data before the aborting,
bus error will occur.

ata_exec_internal_sg
  ->ata_port_freeze if timeout
    ->ata_qc_complete
      ->ata_sg_clean
                                      dma transferring data = bus error
  ->ap->ops->post_internal_cmd
    ->sas_ata_post_internal
      ->sas_ata_internal_abort
        ->abort the cmd

Fix this by moving post_internal_cmd() before unmapping the DMA memory
when time out. Notice that we have to set ATA_QCFLAG_FAILED flag before
calling post_internal_cmd() so that the aborting will work.
Reported-by: Nluojian <luojian5@huawei.com>
Signed-off-by: NJason Yan <yanaijie@huawei.com>
Reviewed-by: Nzhengbin <zhengbin13@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 80006f66
...@@ -1665,6 +1665,13 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, ...@@ -1665,6 +1665,13 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
*/ */
if (qc->flags & ATA_QCFLAG_ACTIVE) { if (qc->flags & ATA_QCFLAG_ACTIVE) {
qc->err_mask |= AC_ERR_TIMEOUT; qc->err_mask |= AC_ERR_TIMEOUT;
qc->flags |= ATA_QCFLAG_FAILED;
spin_unlock_irqrestore(ap->lock, flags);
/* do post_internal_cmd */
if (ap->ops->post_internal_cmd)
ap->ops->post_internal_cmd(qc);
spin_lock_irqsave(ap->lock, flags);
if (ap->ops->error_handler) if (ap->ops->error_handler)
ata_port_freeze(ap); ata_port_freeze(ap);
...@@ -1679,9 +1686,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, ...@@ -1679,9 +1686,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
spin_unlock_irqrestore(ap->lock, flags); spin_unlock_irqrestore(ap->lock, flags);
} }
/* do post_internal_cmd */ if (!(qc->err_mask & AC_ERR_TIMEOUT))
if (ap->ops->post_internal_cmd) /* do post_internal_cmd */
ap->ops->post_internal_cmd(qc); if (ap->ops->post_internal_cmd)
ap->ops->post_internal_cmd(qc);
/* perform minimal error analysis */ /* perform minimal error analysis */
if (qc->flags & ATA_QCFLAG_FAILED) { if (qc->flags & ATA_QCFLAG_FAILED) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册