dmaengine: idxd: make submit failure path consistent on desc freeing
authorDave Jiang <dave.jiang@intel.com>
Fri, 6 Aug 2021 17:37:40 +0000 (10:37 -0700)
committerVinod Koul <vkoul@kernel.org>
Wed, 25 Aug 2021 11:30:24 +0000 (17:00 +0530)
The submission path for dmaengine API does not do descriptor freeing on
failure. Also, with the abort mechanism, the freeing of descriptor happens
when the abort callback is completed. Therefore free descriptor on all
error paths for submission call to make things consistent. Also remove the
double free that would happen on abort in idxd_dma_tx_submit() call.

Fixes: 6b4b87f2c31a ("dmaengine: idxd: fix submission race window")
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/162827146072.3459011.10255348500504659810.stgit@djiang5-desk3.ch.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/idxd/dma.c
drivers/dma/idxd/submit.c

index a195225687bb7f8f983b81effb1a49b1809122c1..5c0a4d8a31f5e796a1cb79931b508832cec7c476 100644 (file)
@@ -149,10 +149,8 @@ static dma_cookie_t idxd_dma_tx_submit(struct dma_async_tx_descriptor *tx)
        cookie = dma_cookie_assign(tx);
 
        rc = idxd_submit_desc(wq, desc);
-       if (rc < 0) {
-               idxd_free_desc(wq, desc);
+       if (rc < 0)
                return rc;
-       }
 
        return cookie;
 }
index 4b514c63af15e9f36a27f168976e56d0dc034766..de76fb4abac24af94f143f5255ff51aa8fe93c37 100644 (file)
@@ -139,11 +139,15 @@ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc)
        void __iomem *portal;
        int rc;
 
-       if (idxd->state != IDXD_DEV_ENABLED)
+       if (idxd->state != IDXD_DEV_ENABLED) {
+               idxd_free_desc(wq, desc);
                return -EIO;
+       }
 
-       if (!percpu_ref_tryget_live(&wq->wq_active))
+       if (!percpu_ref_tryget_live(&wq->wq_active)) {
+               idxd_free_desc(wq, desc);
                return -ENXIO;
+       }
 
        portal = idxd_wq_portal_addr(wq);
 
@@ -175,8 +179,11 @@ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc)
                rc = enqcmds(portal, desc->hw);
                if (rc < 0) {
                        percpu_ref_put(&wq->wq_active);
+                       /* abort operation frees the descriptor */
                        if (ie)
                                llist_abort_desc(wq, ie, desc);
+                       else
+                               idxd_free_desc(wq, desc);
                        return rc;
                }
        }