msm: kgsl: Fix memory leak for anonymous buffers

Currently, clean up is not done properly for anonymous buffer
(KGSL_MEM_ENTRY_USER). Fix it by freeing up resources allocated
during memdesc_sg_virt.

Change-Id: I75bff2e718b494c102a8075a5f27323e1823b212
Signed-off-by: Kamal Agrawal <kamaagra@codeaurora.org>
This commit is contained in:
Kamal Agrawal 2021-07-02 12:20:47 +05:30 • committed by Gerrit - the friendly Code Review server
commit 3121593f88

View file

@ -321,22 +321,57 @@ static void remove_dmabuf_list(struct kgsl_dma_buf_meta *meta)
}
#ifdef CONFIG_DMA_SHARED_BUFFER
static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta)
static void kgsl_destroy_ion(struct kgsl_memdesc *memdesc)
{
struct kgsl_mem_entry *entry = container_of(memdesc,
struct kgsl_mem_entry, memdesc);
struct kgsl_dma_buf_meta *meta = entry->priv_data;
if (meta != NULL) {
remove_dmabuf_list(meta);
dma_buf_detach(meta->dmabuf, meta->attach);
dma_buf_put(meta->dmabuf);
kfree(meta);
}
}
#else
static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta)
{
memdesc->sgt = NULL;
}
static const struct kgsl_memdesc_ops kgsl_dmabuf_ops = {
.free = kgsl_destroy_ion,
};
#endif
static void kgsl_destroy_anon(struct kgsl_memdesc *memdesc)
{
int i = 0, j;
struct scatterlist *sg;
struct page *page;
for_each_sg(memdesc->sgt->sgl, sg, memdesc->sgt->nents, i) {
page = sg_page(sg);
for (j = 0; j < (sg->length >> PAGE_SHIFT); j++) {
/*
* Mark the page in the scatterlist as dirty if they
* were writable by the GPU.
*/
if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
set_page_dirty_lock(nth_page(page, j));
/*
* Put the page reference taken using get_user_pages
* during memdesc_sg_virt.
*/
put_page(nth_page(page, j));
}
}
sg_free_table(memdesc->sgt);
kfree(memdesc->sgt);
memdesc->sgt = NULL;
}
static void kgsl_process_sub_stats(struct kgsl_process_private *priv,
unsigned int type, uint64_t size)
{
@ -381,41 +416,8 @@ kgsl_mem_entry_destroy(struct kref *kref)
atomic_long_sub(entry->memdesc.size,
&kgsl_driver.stats.mapped);
/*
* Ion takes care of freeing the sg_table for us so
* clear the sg table before freeing the sharedmem
* so kgsl_sharedmem_free doesn't try to free it again
*/
if (memtype == KGSL_MEM_ENTRY_ION)
entry->memdesc.sgt = NULL;
if ((memtype == KGSL_MEM_ENTRY_USER)
&& !(entry->memdesc.flags & KGSL_MEMFLAGS_GPUREADONLY)) {
int i = 0, j;
struct scatterlist *sg;
struct page *page;
/*
* Mark all of pages in the scatterlist as dirty since they
* were writable by the GPU.
*/
for_each_sg(entry->memdesc.sgt->sgl, sg,
entry->memdesc.sgt->nents, i) {
page = sg_page(sg);
for (j = 0; j < (sg->length >> PAGE_SHIFT); j++)
set_page_dirty_lock(nth_page(page, j));
}
}
kgsl_sharedmem_free(&entry->memdesc);
switch (memtype) {
case KGSL_MEM_ENTRY_ION:
kgsl_destroy_ion(entry->priv_data);
break;
default:
break;
}
kfree(entry);
}
@ -2524,6 +2526,10 @@ out:
return ret;
}
static const struct kgsl_memdesc_ops kgsl_usermem_ops = {
.free = kgsl_destroy_anon,
};
static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable,
struct kgsl_mem_entry *entry, unsigned long hostptr,
size_t offset, size_t size)
@ -2539,6 +2545,7 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable,
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = (uint64_t) size;
entry->memdesc.flags |= (uint64_t)KGSL_MEMFLAGS_USERMEM_ADDR;
entry->memdesc.ops = &kgsl_usermem_ops;
if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
@ -2879,11 +2886,6 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv,
return 0;
unmap:
if (kgsl_memdesc_usermem_type(&entry->memdesc) == KGSL_MEM_ENTRY_ION) {
kgsl_destroy_ion(entry->priv_data);
entry->memdesc.sgt = NULL;
}
kgsl_sharedmem_free(&entry->memdesc);
out:
@ -2988,6 +2990,7 @@ static int kgsl_setup_dma_buf(struct kgsl_device *device,
entry->priv_data = meta;
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = 0;
entry->memdesc.ops = &kgsl_dmabuf_ops;
/* USE_CPU_MAP is not impemented for ION. */
entry->memdesc.flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP);
entry->memdesc.flags |= (uint64_t)KGSL_MEMFLAGS_USERMEM_ION;
@ -3200,14 +3203,6 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
return result;
error_attach:
switch (kgsl_memdesc_usermem_type(&entry->memdesc)) {
case KGSL_MEM_ENTRY_ION:
kgsl_destroy_ion(entry->priv_data);
entry->memdesc.sgt = NULL;
break;
default:
break;
}
kgsl_sharedmem_free(&entry->memdesc);
error:
/* Clear gpuaddr here so userspace doesn't get any wrong ideas */