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 <xianbing.zhu@linux.alibaba.com>
Change-Id: I8c2a83b60f7d6ff26771550cc691db6b27b73609
Signed-off-by: Han Gao <gaohan@iscas.ac.cn>
This commit is contained in:
Han Gao
2024-07-20 15:45:50 +08:00
committed by Han Gao
parent d2247b2403
commit 8e7282e217

View File

@@ -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)