]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
video: tegra: nvmap: track vma for all handles
authorKrishna Reddy <vdumpa@nvidia.com>
Wed, 4 Jun 2014 21:50:05 +0000 (14:50 -0700)
committerSimone Willett <swillett@nvidia.com>
Fri, 20 Jun 2014 17:54:29 +0000 (10:54 -0700)
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>
drivers/video/tegra/nvmap/nvmap_dev.c
drivers/video/tegra/nvmap/nvmap_handle.c
drivers/video/tegra/nvmap/nvmap_ioctl.c
drivers/video/tegra/nvmap/nvmap_mm.c
drivers/video/tegra/nvmap/nvmap_priv.h

index 4b2e9f3641f2219ca4cea538c6106fec51200fe0..6ae8e7190855d1b0e89168a417742637b7624f26 100644 (file)
@@ -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)
index cdbf6ee65fad8778aba4d5bd63c44a6b6d000f2d..0959a98d5bf41db3687d6908f083c12d5bf641ba 100644 (file)
@@ -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
index a3d39f5096330d04aaaa92365da0a24b0f87497b..d9853e179f85e9f512dd4ea839c967a6d68b7636 100644 (file)
@@ -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);
index 16265859ecd2b0969cc7a59c0ae5860e79f40b96..942394c23f788a23ecc9989fcc2cb55fc31a71ca 100644 (file)
@@ -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;
index 79a9578816892b4bc77efafcb859c54d57dbfd90..7489263c8c629843308333759e3568af59a4c874 100644 (file)
@@ -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);