diff options
author | Krishna Reddy <vdumpa@nvidia.com> | 2014-06-04 14:50:05 -0700 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2014-06-20 10:54:29 -0700 |
commit | 94fd317bb047d52f247071e648b591eb8c51489b (patch) | |
tree | bcdb267a57203036280430ed2212f09619926972 /drivers/video | |
parent | 8b9f817699f6e828f3a224978e242ad79239046c (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')
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_dev.c | 56 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_handle.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_ioctl.c | 33 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_mm.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_priv.h | 2 |
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(¤t->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(¤t->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); |