lkml.org 
[lkml]   [2020]   [Feb]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.14 092/237] dmaengine: Store module owner in dma_device struct
    Date
    From: Logan Gunthorpe <logang@deltatee.com>

    [ Upstream commit dae7a589c18a4d979d5f14b09374e871b995ceb1 ]

    dma_chan_to_owner() dereferences the driver from the struct device to
    obtain the owner and call module_[get|put](). However, if the backing
    device is unbound before the dma_device is unregistered, the driver
    will be cleared and this will cause a NULL pointer dereference.

    Instead, store a pointer to the owner module in the dma_device struct
    so the module reference can be properly put when the channel is put, even
    if the backing device was destroyed first.

    This change helps to support a safer unbind of DMA engines.
    If the dma_device is unregistered in the driver's remove function,
    there's no guarantee that there are no existing clients and a users
    action may trigger the WARN_ONCE in dma_async_device_unregister()
    which is unlikely to leave the system in a consistent state.
    Instead, a better approach is to allow the backing driver to go away
    and fail any subsequent requests to it.

    Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
    Link: https://lore.kernel.org/r/20191216190120.21374-2-logang@deltatee.com
    Signed-off-by: Vinod Koul <vkoul@kernel.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/dma/dmaengine.c | 4 +++-
    include/linux/dmaengine.h | 2 ++
    2 files changed, 5 insertions(+), 1 deletion(-)

    diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
    index b451354735d3d..faaaf10311ec0 100644
    --- a/drivers/dma/dmaengine.c
    +++ b/drivers/dma/dmaengine.c
    @@ -192,7 +192,7 @@ __dma_device_satisfies_mask(struct dma_device *device,

    static struct module *dma_chan_to_owner(struct dma_chan *chan)
    {
    - return chan->device->dev->driver->owner;
    + return chan->device->owner;
    }

    /**
    @@ -928,6 +928,8 @@ int dma_async_device_register(struct dma_device *device)
    return -EIO;
    }

    + device->owner = device->dev->driver->owner;
    +
    if (dma_has_cap(DMA_MEMCPY, device->cap_mask) && !device->device_prep_dma_memcpy) {
    dev_err(device->dev,
    "Device claims capability %s, but op is not defined\n",
    diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
    index 087cbe7768680..8089e28539f16 100644
    --- a/include/linux/dmaengine.h
    +++ b/include/linux/dmaengine.h
    @@ -677,6 +677,7 @@ struct dma_filter {
    * @fill_align: alignment shift for memset operations
    * @dev_id: unique device ID
    * @dev: struct device reference for dma mapping api
    + * @owner: owner module (automatically set based on the provided dev)
    * @src_addr_widths: bit mask of src addr widths the device supports
    * @dst_addr_widths: bit mask of dst addr widths the device supports
    * @directions: bit mask of slave direction the device supports since
    @@ -738,6 +739,7 @@ struct dma_device {

    int dev_id;
    struct device *dev;
    + struct module *owner;

    u32 src_addr_widths;
    u32 dst_addr_widths;
    --
    2.20.1


    \
     
     \ /
      Last update: 2020-02-27 15:39    [W:4.084 / U:0.144 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site