mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-11 05:17:10 +09:00
video: tegra: nvmap: Fix handle ref counting
In the current implementation handles hold references to a client and clients hold references to their handles. As a result when a process terminates it's handles can't be cleaned up and we leak memory. Instead only hold references to handles from clients. Change-Id: Iba699e740a043deaf0a78b13b4ea01544675078f Signed-off-by: Rebecca Schultz Zavin <rebecca@android.com>
This commit is contained in:
@@ -71,6 +71,7 @@ struct nvmap_handle {
|
||||
size_t size; /* padded (as-allocated) size */
|
||||
size_t orig_size; /* original (as-requested) size */
|
||||
struct nvmap_client *owner;
|
||||
struct nvmap_device *dev;
|
||||
union {
|
||||
struct nvmap_pgalloc pgalloc;
|
||||
struct nvmap_heap_block *carveout;
|
||||
@@ -79,6 +80,7 @@ struct nvmap_handle {
|
||||
bool secure; /* zap IOVMM area on unpin */
|
||||
bool heap_pgalloc; /* handle is page allocated (sysmem / iovmm) */
|
||||
bool alloc; /* handle has memory allocated */
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
struct nvmap_share {
|
||||
@@ -161,6 +163,8 @@ void nvmap_carveout_commit_subtract(struct nvmap_client *client,
|
||||
struct nvmap_carveout_node *node,
|
||||
size_t len);
|
||||
|
||||
struct nvmap_share *nvmap_get_share_from_dev(struct nvmap_device *dev);
|
||||
|
||||
struct nvmap_handle *nvmap_validate_get(struct nvmap_client *client,
|
||||
unsigned long handle);
|
||||
|
||||
|
||||
@@ -119,6 +119,11 @@ struct device *nvmap_client_to_device(struct nvmap_client *client)
|
||||
return client->dev->dev_user.this_device;
|
||||
}
|
||||
|
||||
struct nvmap_share *nvmap_get_share_from_dev(struct nvmap_device *dev)
|
||||
{
|
||||
return &dev->iovmm_master;
|
||||
}
|
||||
|
||||
/* allocates a PTE for the caller's use; returns the PTE pointer or
|
||||
* a negative errno. may be called from IRQs */
|
||||
pte_t **nvmap_alloc_pte_irq(struct nvmap_device *dev, void **vaddr)
|
||||
@@ -289,6 +294,9 @@ void nvmap_carveout_commit_subtract(struct nvmap_client *client,
|
||||
struct nvmap_carveout_node *node,
|
||||
size_t len)
|
||||
{
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
mutex_lock(&node->clients_mutex);
|
||||
client->carveout_commit[node->index].commit -= len;
|
||||
BUG_ON(client->carveout_commit[node->index].commit < 0);
|
||||
@@ -472,6 +480,11 @@ static void destroy_client(struct nvmap_client *client)
|
||||
smp_rmb();
|
||||
pins = atomic_read(&ref->pin);
|
||||
|
||||
mutex_lock(&ref->handle->lock);
|
||||
if (ref->handle->owner == client)
|
||||
ref->handle->owner = NULL;
|
||||
mutex_unlock(&ref->handle->lock);
|
||||
|
||||
while (pins--)
|
||||
nvmap_unpin_handles(client, &ref->handle, 1);
|
||||
|
||||
|
||||
@@ -71,19 +71,21 @@ static inline void altfree(void *ptr, size_t len)
|
||||
|
||||
void _nvmap_handle_free(struct nvmap_handle *h)
|
||||
{
|
||||
struct nvmap_client *client = h->owner;
|
||||
struct nvmap_device *dev = h->dev;
|
||||
unsigned int i, nr_page;
|
||||
|
||||
if (nvmap_handle_remove(client->dev, h) != 0)
|
||||
if (nvmap_handle_remove(dev, h) != 0)
|
||||
return;
|
||||
|
||||
if (!h->alloc)
|
||||
goto out;
|
||||
|
||||
if (!h->heap_pgalloc) {
|
||||
nvmap_carveout_commit_subtract(client,
|
||||
mutex_lock(&h->lock);
|
||||
nvmap_carveout_commit_subtract(h->owner,
|
||||
nvmap_heap_to_arg(nvmap_block_to_heap(h->carveout)),
|
||||
h->size);
|
||||
mutex_unlock(&h->lock);
|
||||
nvmap_heap_free(h->carveout);
|
||||
goto out;
|
||||
}
|
||||
@@ -93,7 +95,8 @@ void _nvmap_handle_free(struct nvmap_handle *h)
|
||||
BUG_ON(h->size & ~PAGE_MASK);
|
||||
BUG_ON(!h->pgalloc.pages);
|
||||
|
||||
nvmap_mru_remove(client->share, h);
|
||||
nvmap_mru_remove(nvmap_get_share_from_dev(dev), h);
|
||||
|
||||
if (h->pgalloc.area)
|
||||
tegra_iovmm_free_vm(h->pgalloc.area);
|
||||
|
||||
@@ -104,7 +107,6 @@ void _nvmap_handle_free(struct nvmap_handle *h)
|
||||
|
||||
out:
|
||||
kfree(h);
|
||||
nvmap_client_put(client);
|
||||
}
|
||||
|
||||
extern void __flush_dcache_page(struct address_space *, struct page *);
|
||||
@@ -423,10 +425,12 @@ struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client,
|
||||
|
||||
atomic_set(&h->ref, 1);
|
||||
atomic_set(&h->pin, 0);
|
||||
h->owner = nvmap_client_get(client);
|
||||
h->owner = client;
|
||||
h->dev = client->dev;
|
||||
BUG_ON(!h->owner);
|
||||
h->size = h->orig_size = size;
|
||||
h->flags = NVMAP_HANDLE_WRITE_COMBINE;
|
||||
mutex_init(&h->lock);
|
||||
|
||||
nvmap_handle_add(client->dev, h);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user