From 8e7282e217e07f756179ab6099c80d57207b189f Mon Sep 17 00:00:00 2001 From: Han Gao Date: Sat, 20 Jul 2024 15:45:50 +0800 Subject: [PATCH] vidmem:kernel: fixup unsafe release of allocater and dmabuf This commit fixup unsafe release of allocater and dmabuf. have merged vidmem:kernel: update dmabuf release not free by allocate release. Prev commit add release of dmabuf may caused mem node list removed racing.Here have moved the exported node to global list. Signed-off-by: xianbing Zhu Change-Id: I8c2a83b60f7d6ff26771550cc691db6b27b73609 Signed-off-by: Han Gao --- .../video/video_memory/driver/video_memory.c | 121 +++++++++++++----- 1 file changed, 89 insertions(+), 32 deletions(-) diff --git a/drivers/video/video_memory/driver/video_memory.c b/drivers/video/video_memory/driver/video_memory.c index 0f8112926..e892e659d 100644 --- a/drivers/video/video_memory/driver/video_memory.c +++ b/drivers/video/video_memory/driver/video_memory.c @@ -235,6 +235,7 @@ struct mem_node struct mem_block memBlk; unsigned long busAddr; int isImported; + int isExported; struct list_head link; }; @@ -246,6 +247,9 @@ struct file_node }; static struct list_head fileList; +/* golbal list for exported mem_node */ +static struct list_head export_list; +static DEFINE_SPINLOCK(export_mem_lock); static int vidalloc_major = 0; static int vidalloc_minor = 0; @@ -262,11 +266,7 @@ getPhysical( IN unsigned int Offset, OUT unsigned long * Physical ); -void -GFP_Free( - IN struct file *filp, - IN unsigned long bus_address - ); +void free_memblk_pages(struct mem_block *memBlk); static struct file_node * find_and_delete_file_node(struct file *filp) { @@ -306,6 +306,23 @@ static struct file_node * get_file_node(struct file *filp) return NULL; } +static struct mem_node * get_export_mem_node(struct file *filp, unsigned long bus_address) +{ + struct mem_node *node; + spin_lock(&export_mem_lock); + list_for_each_entry(node, &export_list, link) + { + if (node->busAddr == bus_address) + { + DEBUG_PRINT("[vidmem] Found export mem node %px, %d pages\n", node); + spin_unlock(&export_mem_lock); + return node; + } + } + spin_unlock(&export_mem_lock); + return NULL; +} + static struct mem_node * get_mem_node(struct file *filp, unsigned long bus_address, int imported) { struct file_node *fnode; @@ -328,6 +345,7 @@ static struct mem_node * get_mem_node(struct file *filp, unsigned long bus_addre } spin_unlock(&mem_lock); + return NULL; } @@ -457,7 +475,9 @@ static void invalid_data_cache(IN struct file *filp, IN unsigned long bus_addres mnode = get_mem_node(filp, bus_address, 0); if (NULL == mnode) { - return; + mnode = get_export_mem_node(filp, bus_address); + if (NULL == mnode) + return; } memBlk = &mnode->memBlk; @@ -475,7 +495,9 @@ static void flush_data_cache(IN struct file *filp, IN unsigned long bus_address mnode = get_mem_node(filp, bus_address, 0); if (NULL == mnode) { - return; + mnode = get_export_mem_node(filp, bus_address); + if (NULL == mnode) + return; } memBlk = &mnode->memBlk; @@ -709,7 +731,8 @@ static void _dmabuf_release(struct dma_buf *dmabuf) { struct mem_block *memBlk = dmabuf->priv; unsigned long physical; - + //struct mem_node *mnode = (mem_node *)memBlk; + struct mem_node *mnode = container_of(memBlk,struct mem_node,memBlk); if (!memBlk) return; if(!memBlk->filp) @@ -718,9 +741,17 @@ static void _dmabuf_release(struct dma_buf *dmabuf) return; } getPhysical(memBlk, 0, &physical); - DEBUG_PRINT("[vidmem] %s, %d: free physical %llx\n", __func__, __LINE__,physical); - GFP_Free(memBlk->filp,physical); + DEBUG_PRINT("[vidmem] %s, %d: free physical %llx,mnode %px\n", __func__, __LINE__,physical,mnode); + free_memblk_pages(memBlk); + DEBUG_PRINT(" %s: remove node\n",__func__); + //remove node from export gloabl list + spin_lock(&export_mem_lock); + list_del(&mnode->link); + spin_unlock(&export_mem_lock); + DEBUG_PRINT(" %s: FreeMemory of node\n",__func__); + FreeMemory(mnode); + dmabuf->priv = NULL; } static void *_dmabuf_kmap(struct dma_buf *dmabuf, unsigned long offset) @@ -770,6 +801,7 @@ DMABUF_Export( memBlk = &mnode->memBlk; memBlk->filp = filp; + mnode->isExported = 1; dmabuf = memBlk->dmabuf; if (dmabuf == NULL) @@ -803,8 +835,18 @@ DMABUF_Export( } *FD = fd; + DEBUG_PRINT(" [vidmem] Export as fd %d,mnode %px memBlk %px\n", fd,mnode,&mnode->memBlk); } + /*exported buffer remove from list*/ + spin_lock(&mem_lock); + list_del(&mnode->link); + spin_unlock(&mem_lock); + + /* add to export gloabl list*/ + spin_lock(&export_mem_lock); + list_add_tail(&mnode->link,&export_list); + spin_unlock(&export_mem_lock); OnError: return status; } @@ -879,7 +921,7 @@ DMABUF_Release( { struct mem_block *memBlk = NULL; struct mem_node *mnode = NULL; - + DEBUG_PRINT("[vidmem] enter %s: bus_address 0x%lx\n",__func__, bus_address); mnode = get_mem_node(filp, bus_address, 1); if (NULL == mnode) { @@ -896,6 +938,7 @@ DMABUF_Release( FreeMemory(memBlk->pagearray); + DEBUG_PRINT("[vidmem] release bus address at 0x%lx in size of %ld\n", bus_address, memBlk->size); spin_lock(&mem_lock); list_del(&mnode->link); spin_unlock(&mem_lock); @@ -1204,7 +1247,9 @@ OnDone: *bus_address = physical; mnode->busAddr = physical; mnode->isImported = 0; + spin_lock(&mem_lock); list_add_tail(&mnode->link, &fnode->memList); + spin_unlock(&mem_lock); DEBUG_PRINT("[vidmem] Allocated %d bytes (%ld pages) at physical address 0x%lx with %d sg table entries\n", size, numPages, physical, contiguous ? 1 : memBlk->sgt->nents); @@ -1225,27 +1270,11 @@ OnError: return status; } - -void -GFP_Free( - IN struct file *filp, - IN unsigned long bus_address - ) +void free_memblk_pages(struct mem_block *memBlk) { size_t i; struct page * page; - struct mem_block *memBlk = NULL; - struct mem_node *mnode = NULL; - - mnode = get_mem_node(filp, bus_address, 0); - if (NULL == mnode) - { - return; - } - - memBlk = &mnode->memBlk; - - DEBUG_PRINT("[vidmem] Free %ld pages from physical address 0x%lx\n", memBlk->numPages, mnode->busAddr); + DEBUG_PRINT(" ##[vidmem] Free %ld pages, contiguous %d\n", memBlk->numPages, memBlk->contiguous); if (memBlk->contiguous) { @@ -1306,6 +1335,27 @@ GFP_Free( { NonContiguousFree(memBlk->nonContiguousPages, memBlk->numPages); } +} + +void +GFP_Free( + IN struct file *filp, + IN unsigned long bus_address + ) +{ + struct mem_block *memBlk = NULL; + struct mem_node *mnode = NULL; + + mnode = get_mem_node(filp, bus_address, 0); + if (NULL == mnode) + { + return; + } + + memBlk = &mnode->memBlk; + DEBUG_PRINT("[vidmem] Free %ld pages from physical address 0x%lx\n", memBlk->numPages, mnode->busAddr); + + free_memblk_pages(memBlk); spin_lock(&mem_lock); list_del(&mnode->link); @@ -1327,7 +1377,9 @@ GFP_MapUser( mnode = get_mem_node(filp, bus_address, 0); if (NULL == mnode) { - return EINVAL; + mnode = get_export_mem_node(filp, bus_address); + if (NULL == mnode) + return EINVAL; } memBlk = &mnode->memBlk; @@ -1471,7 +1523,11 @@ static int vidalloc_release(struct inode *inode, struct file *filp) list_for_each_entry_safe(node, temp, &fnode->memList, link) { // this is not expected, memory leak detected! - pr_debug("vidmem: Found unfreed memory at 0x%lx, isImported = %d\n", node->busAddr, node->isImported); + pr_debug("vidmem: Found unfreed memory at 0x%lx, isImported = %d isExported = %d\n", node->busAddr, node->isImported,node->isExported); + if (node->isExported) //let dmabuf release ops free + { + continue; + } if (node->isImported) DMABUF_Release(filp, node->busAddr); else @@ -1501,10 +1557,11 @@ int vidalloc_probe(struct platform_device *pdev) { int result = 0; - DEBUG_PRINT("enter %s\n",__func__); + pr_info("enter %s,ver:1.2A\n",__func__); #if 1 gdev = &pdev->dev; INIT_LIST_HEAD(&fileList); + INIT_LIST_HEAD(&export_list); result = rsvmem_pool_create(&pdev->dev); if (result && result != -ENODEV)