dmaengine: xilinx_dma: Add missing check for empty list
authorSebastian von Ohr <vonohr@smaract.com>
Tue, 3 Mar 2020 13:05:18 +0000 (14:05 +0100)
committerVinod Koul <vkoul@kernel.org>
Wed, 15 Apr 2020 16:12:11 +0000 (21:42 +0530)
The DMA transfer might finish just after checking the state with
dma_cookie_status, but before the lock is acquired. Not checking
for an empty list in xilinx_dma_tx_status may result in reading
random data or data corruption when desc is written to. This can
be reliably triggered by using dma_sync_wait to wait for DMA
completion.

Signed-off-by: Sebastian von Ohr <vonohr@smaract.com>
Tested-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
Link: https://lore.kernel.org/r/20200303130518.333-1-vonohr@smaract.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/xilinx/xilinx_dma.c

index aecd5a3..5429497 100644 (file)
@@ -1230,16 +1230,16 @@ static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan,
                return ret;
 
        spin_lock_irqsave(&chan->lock, flags);
-
-       desc = list_last_entry(&chan->active_list,
-                              struct xilinx_dma_tx_descriptor, node);
-       /*
-        * VDMA and simple mode do not support residue reporting, so the
-        * residue field will always be 0.
-        */
-       if (chan->has_sg && chan->xdev->dma_config->dmatype != XDMA_TYPE_VDMA)
-               residue = xilinx_dma_get_residue(chan, desc);
-
+       if (!list_empty(&chan->active_list)) {
+               desc = list_last_entry(&chan->active_list,
+                                      struct xilinx_dma_tx_descriptor, node);
+               /*
+                * VDMA and simple mode do not support residue reporting, so the
+                * residue field will always be 0.
+                */
+               if (chan->has_sg && chan->xdev->dma_config->dmatype != XDMA_TYPE_VDMA)
+                       residue = xilinx_dma_get_residue(chan, desc);
+       }
        spin_unlock_irqrestore(&chan->lock, flags);
 
        dma_set_residue(txstate, residue);