dmaengine: Fix broken device refcounting
PATCH 1/1 dmaengine: Fix broken device refcounting
From: Haavard Skinnemoen <[email protected]>
When a DMA device is unregistered, its reference count is decremented twice for each channel: Once dma_class_dev_release() and once in dma_chan_cleanup(). This may result in the DMA device driver's remove() function completing before all channels have been cleaned up, causing lots of use-after-free fun.
Fix it by incrementing the device's reference count twice for each channel during registration.
---
This fixes dmaengine refcounting in 2.6.23.y and 2.6.24-rc.
drivers/dma/dmaengine.c | 17 ++++++----------- 1 files changed, 6 insertions(+), 11 deletions(-)
drivers/dma/dmaengine.c +6 -11
@@ -186,10 +186,9 @@ static void dma_client_chan_alloc(struct dma_client *client)/* we are done once this client rejects * an available resource */ -if (ack ==DMA_ACK ) { +if (ack ==DMA_ACK )dma_chan_get (chan); -kref_get (&device->refcount); - }else if (ack ==DMA_NAK ) +else if (ack ==DMA_NAK )return ; } }
@@ -276,11 +275,8 @@ static void dma_clients_notify_removed(struct dma_chan *chan)/* client was holding resources for this channel so * free it */ -if (ack ==DMA_ACK ) { +if (ack ==DMA_ACK )dma_chan_put (chan); -kref_put (&chan->device->refcount, - dma_async_device_cleanup); - } }mutex_unlock (&dma_list_mutex);
@@ -320,11 +316,8 @@ void dma_async_client_unregister(struct dma_client *client) ack = client->event_callback (client, chan,DMA_RESOURCE_REMOVED ); -if (ack ==DMA_ACK ) { +if (ack ==DMA_ACK )dma_chan_put (chan); -kref_put (&chan->device->refcount, - dma_async_device_cleanup); - } }list_del (&client->global_node);
@@ -401,6 +394,8 @@ int dma_async_device_register(struct dma_device *device) goto err_out; } +/* One for the channel, one of the class device */ +kref_get (&device->refcount);kref_get (&device->refcount);kref_init (&chan->refcount); chan->slow_ref =0 ;
Quoted 8 lines · Dan Williams
From: Haavard Skinnemoen <[email protected]>
When a DMA device is unregistered, its reference count is decremented twice for each channel: Once
dma_class_dev_release()and once indma_chan_cleanup(). This may result in the DMA device driver'sremove()function completing before all channels have been cleaned up, causing lots of use-after-free fun.
Quoted 8 lines
Fix it by incrementing the device's reference count twice for each channel during registration.
Signed-off-by Haavard Skinnemoen <[email protected]>[[email protected]: kill unnecessary client refcounting]Signed-off-by Dan Williams <[email protected]>Signed-off-by Shannon Nelson <[email protected]>
I don't see this in Linus's tree yet, right?
When it goes in, can you resend it to the [email protected] people?
thanks,
greg k-h