summaryrefslogtreecommitdiff
path: root/drivers/video/tegra
diff options
context:
space:
mode:
authorKrishna Reddy <vdumpa@nvidia.com>2014-06-04 14:50:05 -0700
committerSimone Willett <swillett@nvidia.com>2014-06-20 10:54:29 -0700
commit94fd317bb047d52f247071e648b591eb8c51489b (patch)
treebcdb267a57203036280430ed2212f09619926972 /drivers/video/tegra
parent8b9f817699f6e828f3a224978e242ad79239046c (diff)
video: tegra: nvmap: track vma for all handles
Clean up the code related to mmap and handle nvmap_map_info_caller_ptr failures graciously. Initilize h->vmas at right place. Add sanity checks in nvmap_vma_open/_close. Bug 1519700 Change-Id: Iede355b8a500a787992fcb23a72cf334a737ec49 Signed-off-by: Krishna Reddy <vdumpa@nvidia.com> Reviewed-on: http://git-master/r/419168 (cherry picked from commit c18228c5de319d74f68deff9c5d402ca17b64e95) Signed-off-by: Sri Krishna chowdary <schowdary@nvidia.com> Reviewed-on: http://git-master/r/426092 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'drivers/video/tegra')
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c56
-rw-r--r--drivers/video/tegra/nvmap/nvmap_handle.c2
-rw-r--r--drivers/video/tegra/nvmap/nvmap_ioctl.c33
-rw-r--r--drivers/video/tegra/nvmap/nvmap_mm.c2
-rw-r--r--drivers/video/tegra/nvmap/nvmap_priv.h2
5 files changed, 41 insertions, 54 deletions
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c
index 4b2e9f3641f2..6ae8e7190855 100644
--- a/drivers/video/tegra/nvmap/nvmap_dev.c
+++ b/drivers/video/tegra/nvmap/nvmap_dev.c
@@ -542,21 +542,10 @@ int __nvmap_map(struct nvmap_handle *h, struct vm_area_struct *vma)
static int nvmap_map(struct file *filp, struct vm_area_struct *vma)
{
- struct nvmap_vma_priv *priv;
-
- /* after NVMAP_IOC_MMAP, the handle that is mapped by this VMA
- * will be stored in vm_private_data and faulted in. until the
- * ioctl is made, the VMA is mapped no-access */
- vma->vm_private_data = NULL;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
+ BUG_ON(vma->vm_private_data != NULL);
vma->vm_flags |= (VM_SHARED | VM_DONTEXPAND |
VM_DONTDUMP | VM_DONTCOPY);
vma->vm_ops = &nvmap_vma_ops;
- vma->vm_private_data = priv;
return 0;
}
@@ -689,61 +678,60 @@ void nvmap_vma_open(struct vm_area_struct *vma)
{
struct nvmap_vma_priv *priv;
struct nvmap_handle *h;
- struct nvmap_vma_list *vma_list;
+ struct nvmap_vma_list *vma_list, *tmp;
priv = vma->vm_private_data;
BUG_ON(!priv);
BUG_ON(!priv->handle);
+ atomic_inc(&priv->count);
h = priv->handle;
- if (h->heap_pgalloc) {
- vma_list = kmalloc(sizeof(*vma_list), GFP_KERNEL);
- if (!vma_list) {
- WARN(1, "vma not tracked");
- goto finish;
- }
- vma_list->vma = vma;
- INIT_LIST_HEAD(&vma_list->list);
+
+ vma_list = kmalloc(sizeof(*vma_list), GFP_KERNEL);
+ if (vma_list) {
mutex_lock(&h->lock);
- list_add(&vma_list->list, &h->pgalloc.vmas);
+ list_for_each_entry(tmp, &h->vmas, list)
+ BUG_ON(tmp->vma == vma);
+
+ vma_list->vma = vma;
+ list_add(&vma_list->list, &h->vmas);
mutex_unlock(&h->lock);
+ } else {
+ WARN(1, "vma not tracked");
}
-
-finish:
- atomic_inc(&priv->count);
}
static void nvmap_vma_close(struct vm_area_struct *vma)
{
struct nvmap_vma_priv *priv = vma->vm_private_data;
- struct nvmap_vma_list *vma_list, *tmp;
+ struct nvmap_vma_list *vma_list;
struct nvmap_handle *h;
+ bool vma_found = false;
if (!priv)
- goto finish;
+ return;
- if (!priv->handle || !priv->handle->heap_pgalloc)
- goto try_to_free_priv;
+ BUG_ON(!priv->handle);
h = priv->handle;
mutex_lock(&h->lock);
- list_for_each_entry_safe(vma_list, tmp, &h->pgalloc.vmas, list) {
+ list_for_each_entry(vma_list, &h->vmas, list) {
if (vma_list->vma != vma)
continue;
list_del(&vma_list->list);
kfree(vma_list);
+ vma_found = true;
break;
}
+ BUG_ON(!vma_found);
mutex_unlock(&h->lock);
-try_to_free_priv:
- if (!atomic_dec_return(&priv->count)) {
+ if (__atomic_add_unless(&priv->count, -1, 0) == 1) {
if (priv->handle)
nvmap_handle_put(priv->handle);
+ vma->vm_private_data = NULL;
kfree(priv);
}
-finish:
- vma->vm_private_data = NULL;
}
static int nvmap_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c
index cdbf6ee65fad..0959a98d5bf4 100644
--- a/drivers/video/tegra/nvmap/nvmap_handle.c
+++ b/drivers/video/tegra/nvmap/nvmap_handle.c
@@ -229,7 +229,6 @@ static int handle_page_alloc(struct nvmap_client *client,
h->size = size;
h->pgalloc.pages = pages;
h->pgalloc.contig = contiguous;
- INIT_LIST_HEAD(&h->pgalloc.vmas);
atomic_set(&h->pgalloc.ndirty, 0);
return 0;
@@ -510,6 +509,7 @@ struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client,
h->size = h->orig_size = size;
h->flags = NVMAP_HANDLE_WRITE_COMBINE;
mutex_init(&h->lock);
+ INIT_LIST_HEAD(&h->vmas);
/*
* This takes out 1 ref on the dambuf. This corresponds to the
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.c b/drivers/video/tegra/nvmap/nvmap_ioctl.c
index a3d39f509633..d9853e179f85 100644
--- a/drivers/video/tegra/nvmap/nvmap_ioctl.c
+++ b/drivers/video/tegra/nvmap/nvmap_ioctl.c
@@ -425,7 +425,7 @@ int nvmap_map_into_caller_ptr(struct file *filp, void __user *arg, bool is32)
#ifdef CONFIG_COMPAT
struct nvmap_map_caller_32 op32;
#endif
- struct nvmap_vma_priv *vpriv;
+ struct nvmap_vma_priv *priv;
struct vm_area_struct *vma;
struct nvmap_handle *h = NULL;
int err = 0;
@@ -464,7 +464,7 @@ int nvmap_map_into_caller_ptr(struct file *filp, void __user *arg, bool is32)
down_read(&current->mm->mmap_sem);
vma = find_vma(current->mm, op.addr);
- if (!vma || !vma->vm_private_data) {
+ if (!vma) {
err = -ENOMEM;
goto out;
}
@@ -479,9 +479,6 @@ int nvmap_map_into_caller_ptr(struct file *filp, void __user *arg, bool is32)
goto out;
}
- vpriv = vma->vm_private_data;
- BUG_ON(!vpriv);
-
/* the VMA must exactly match the requested mapping operation, and the
* VMA that is targetted must have been created by this driver
*/
@@ -492,22 +489,24 @@ int nvmap_map_into_caller_ptr(struct file *filp, void __user *arg, bool is32)
}
/* verify that each mmap() system call creates a unique VMA */
-
- if (vpriv->handle && (h == vpriv->handle)) {
+ if (vma->vm_private_data)
goto out;
- } else if (vpriv->handle) {
- err = -EADDRNOTAVAIL;
- goto out;
- }
if (!h->heap_pgalloc && (h->carveout->base & ~PAGE_MASK)) {
err = -EFAULT;
goto out;
}
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ err = -ENOMEM;
+ goto out;
+ }
+
vma->vm_flags |= (h->heap_pgalloc ? 0 : VM_PFNMAP);
- vpriv->handle = h;
- vpriv->offs = op.offset;
+ priv->handle = h;
+ priv->offs = op.offset;
+ vma->vm_private_data = priv;
vma->vm_page_prot = nvmap_pgprot(h, vma->vm_page_prot);
nvmap_vma_open(vma);
@@ -640,7 +639,7 @@ static int __nvmap_cache_maint(struct nvmap_client *client,
struct nvmap_cache_op *op)
{
struct vm_area_struct *vma;
- struct nvmap_vma_priv *vpriv;
+ struct nvmap_vma_priv *priv;
struct nvmap_handle *handle;
unsigned long start;
unsigned long end;
@@ -662,9 +661,9 @@ static int __nvmap_cache_maint(struct nvmap_client *client,
goto out;
}
- vpriv = (struct nvmap_vma_priv *)vma->vm_private_data;
+ priv = (struct nvmap_vma_priv *)vma->vm_private_data;
- if (vpriv->handle != handle) {
+ if (priv->handle != handle) {
err = -EFAULT;
goto out;
}
@@ -673,7 +672,7 @@ static int __nvmap_cache_maint(struct nvmap_client *client,
(vma->vm_pgoff << PAGE_SHIFT);
end = start + op->len;
- err = __nvmap_do_cache_maint(client, vpriv->handle, start, end, op->op,
+ err = __nvmap_do_cache_maint(client, priv->handle, start, end, op->op,
false);
out:
up_read(&current->mm->mmap_sem);
diff --git a/drivers/video/tegra/nvmap/nvmap_mm.c b/drivers/video/tegra/nvmap/nvmap_mm.c
index 16265859ecd2..942394c23f78 100644
--- a/drivers/video/tegra/nvmap/nvmap_mm.c
+++ b/drivers/video/tegra/nvmap/nvmap_mm.c
@@ -190,7 +190,7 @@ void nvmap_zap_handle(struct nvmap_handle *handle, u32 offset, u32 size)
size = PAGE_ALIGN((offset & ~PAGE_MASK) + size);
mutex_lock(&handle->lock);
- vmas = &handle->pgalloc.vmas;
+ vmas = &handle->vmas;
list_for_each_entry(vma_list, vmas, list) {
struct nvmap_vma_priv *priv;
u32 vm_size = size;
diff --git a/drivers/video/tegra/nvmap/nvmap_priv.h b/drivers/video/tegra/nvmap/nvmap_priv.h
index 79a957881689..7489263c8c62 100644
--- a/drivers/video/tegra/nvmap/nvmap_priv.h
+++ b/drivers/video/tegra/nvmap/nvmap_priv.h
@@ -105,7 +105,6 @@ struct nvmap_vma_list {
struct nvmap_pgalloc {
struct page **pages;
bool contig; /* contiguous system memory */
- struct list_head vmas;
atomic_t ndirty; /* count number of dirty pages */
};
@@ -135,6 +134,7 @@ struct nvmap_handle {
bool alloc; /* handle has memory allocated */
u32 userflags; /* flags passed from userspace */
void *vaddr; /* mapping used inside kernel */
+ struct list_head vmas; /* list of all user vma's */
struct mutex lock;
void *nvhost_priv; /* nvhost private data */
void (*nvhost_priv_delete)(void *priv);