summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2024-03-25 02:34:40 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2024-03-25 02:34:38 -0700
commitb26c6031c572601ef1842d25673ad96d1207c84d (patch)
treef4cdbbef58bda896e052ca7cf5ca3ebed4e6f754
parentd764b49bbb724d678cec807309eb43a31917ca3a (diff)
parentb265eab03adfc6c0d1e078a80af29af69735d847 (diff)
Merge "msm: kgsl: Fix memory leak for anonymous buffers"
-rw-r--r--drivers/gpu/msm/kgsl.c97
-rw-r--r--drivers/gpu/msm/kgsl_sharedmem.c3
2 files changed, 48 insertions, 52 deletions
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 3024efab2b58..bc0a9fd27e5b 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2008-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -271,8 +271,12 @@ kgsl_mem_entry_create(void)
return entry;
}
#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) {
dma_buf_unmap_attachment(meta->attach, meta->table,
DMA_FROM_DEVICE);
@@ -280,13 +284,44 @@ static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta)
dma_buf_put(meta->dmabuf);
kfree(meta);
}
+
+ /*
+ * Ion takes care of freeing the sg_table for us so
+ * clear the sg table to ensure kgsl_sharedmem_free
+ * doesn't try to free it again
+ */
+ memdesc->sgt = NULL;
}
-#else
-static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta)
+
+static 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));
+ }
+ }
}
-#endif
void
kgsl_mem_entry_destroy(struct kref *kref)
@@ -309,41 +344,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);
}
EXPORT_SYMBOL(kgsl_mem_entry_destroy);
@@ -2204,6 +2206,10 @@ out:
return ret;
}
+static 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)
@@ -2219,6 +2225,7 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable,
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = (uint64_t) size;
entry->memdesc.flags |= KGSL_MEMFLAGS_USERMEM_ADDR;
+ entry->memdesc.ops = &kgsl_usermem_ops;
if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
@@ -2529,11 +2536,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:
@@ -2630,6 +2632,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 |= KGSL_MEMFLAGS_USERMEM_ION;
@@ -2840,14 +2843,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 */
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index e2b36c5ddfd8..657e699b72d9 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2002,2007-2017,2020-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -881,6 +881,7 @@ void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc)
if (memdesc->sgt) {
sg_free_table(memdesc->sgt);
kfree(memdesc->sgt);
+ memdesc->sgt = NULL;
}
if (memdesc->pages)