mirror of
https://github.com/revyos/thead-kernel.git
synced 2026-06-21 09:12:26 +02:00
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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user