diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-09-20 10:45:22 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-09-20 10:45:22 -0700 |
| commit | a10a019dd4c7c57bef6b8dda962c8881ad220af2 (patch) | |
| tree | c4eb799cc42f73f3efa4bca8328a02ffde94be94 /drivers/dma/dmaengine.c | |
| parent | 60ee24f055f87c74d3fccdedcb761df9253fd5c0 (diff) | |
| parent | 075bc7b1d3dde5ed43fbaabbc1a69f09b7fc3a47 (diff) | |
| download | linux-stable-a10a019dd4c7c57bef6b8dda962c8881ad220af2.tar.gz linux-stable-a10a019dd4c7c57bef6b8dda962c8881ad220af2.zip | |
Merge tag 'dmaengine-fix-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine
Pull dmaengine fixes from Vinod Koul:
- A couple of fixes in core around dma_chan_put() for kref underflow,
use-after-free and waiting for rcu readers for dma devices
- mmp sg length and wrong extended DRCMR base for SpacemiT K3
- hardware buffer descriptor chain fix for xilinx dma
- sun6i fixes for status behaviour and dma position registers
- runtime pm reference leak fix for sprd driver
* tag 'dmaengine-fix-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine:
dmaengine: mmp_pdma: fix wrong sg length in mmp_pdma_prep_slave_sg()
dmaengine: xilinx_dma: Fix hardware buffer descriptor chain after cyclic DMA
dmaengine: pxa: fix double counting of the hw descriptors
dmaengine: sun6i: fix undefined behaviour in sun6i_dma_tx_status
dmaengine: sun6i: fix non-atomic read of DMA position registers
dmaengine: xilinx_dma: Fix hardware buffer descriptor reuse order
dmaengine: wait for RCU readers before releasing dma_device
dmaengine: fix use-after-free in dma_chan_put() and dma_release_channel()
dmaengine: Fix device kref underflow in dma_chan_put()
dmaengine: add dma_device_get() helper
dmaengine: sprd: Fix runtime PM reference leak in probe
dmaengine: ti: k3-udma-glue: fix NULL dereference in k3_udma_glue_release_rx_chn()
dmaengine: mmp_pdma: fix wrong extended DRCMR base for SpacemiT K3
Diffstat (limited to 'drivers/dma/dmaengine.c')
| -rw-r--r-- | drivers/dma/dmaengine.c | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 6ffd8bd82..c71763047 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -428,11 +428,18 @@ static void dma_device_release(struct kref *ref) list_del_rcu(&device->global_node); dma_channel_rebalance(); + synchronize_rcu(); if (device->device_release) device->device_release(device); } +static int __must_check dma_device_get(struct dma_device *device) +{ + lockdep_assert_held(&dma_list_mutex); + return kref_get_unless_zero(&device->ref); +} + static void dma_device_put(struct dma_device *device) { lockdep_assert_held(&dma_list_mutex); @@ -460,8 +467,7 @@ static int dma_chan_get(struct dma_chan *chan) if (!try_module_get(owner)) return -ENODEV; - ret = kref_get_unless_zero(&chan->device->ref); - if (!ret) { + if (!dma_device_get(chan->device)) { ret = -ENODEV; goto module_put_out; } @@ -495,10 +501,13 @@ module_put_out: */ static void dma_chan_put(struct dma_chan *chan) { + struct module *owner; + /* This channel is not in use, bail out */ if (!chan->client_count) return; + owner = dma_chan_to_owner(chan); chan->client_count--; /* This channel is not in use anymore, free it */ @@ -515,8 +524,10 @@ static void dma_chan_put(struct dma_chan *chan) chan->route_data = NULL; } - dma_device_put(chan->device); - module_put(dma_chan_to_owner(chan)); + /* This channel is not in use anymore, drop the device ref */ + if (!chan->client_count) + dma_device_put(chan->device); + module_put(owner); } enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie) |
