gpu: nvgpu: avoid double mapping of usermode mmap region

gk20a_pm_runtime_suspend can fail and invoke gk20a_pm_finalize_poweron
that can cause double mapping of the usermode mmap region via
io_remap_pfn_range(). Avoid this by using a boolean variable to track
whether the region is already mapped.

Bug 2707416
Bug 200582208

Change-Id: I4d8cbe427400a5b986348a19af145367cc08ffc6
Signed-off-by: Debarshi Dutta <ddutta@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/2229312
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2283801
Reviewed-by: Kajetan Dutka <kdutka@nvidia.com>
Reviewed-by: Thomas Fleury <tfleury@nvidia.com>
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: Kajetan Dutka <kdutka@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Debarshi Dutta
2019-10-31 16:03:33 +05:30
committed by mobile promotions
parent 9e9046f03c
commit f0fca24ffb

View File

@@ -60,6 +60,7 @@ struct gk20a_ctrl_priv {
struct { struct {
struct vm_area_struct *vma; struct vm_area_struct *vma;
unsigned long flags; unsigned long flags;
bool vma_mapped;
} usermode_vma; } usermode_vma;
}; };
@@ -1925,6 +1926,7 @@ static void usermode_vma_close(struct vm_area_struct *vma)
nvgpu_mutex_acquire(&l->ctrl.privs_lock); nvgpu_mutex_acquire(&l->ctrl.privs_lock);
priv->usermode_vma.vma = NULL; priv->usermode_vma.vma = NULL;
priv->usermode_vma.vma_mapped = false;
nvgpu_mutex_release(&l->ctrl.privs_lock); nvgpu_mutex_release(&l->ctrl.privs_lock);
} }
@@ -1974,6 +1976,7 @@ int gk20a_ctrl_dev_mmap(struct file *filp, struct vm_area_struct *vma)
priv->usermode_vma.vma = vma; priv->usermode_vma.vma = vma;
priv->usermode_vma.flags = vma->vm_flags; priv->usermode_vma.flags = vma->vm_flags;
vma->vm_private_data = priv; vma->vm_private_data = priv;
priv->usermode_vma.vma_mapped = true;
} }
nvgpu_mutex_release(&l->ctrl.privs_lock); nvgpu_mutex_release(&l->ctrl.privs_lock);
@@ -1988,6 +1991,7 @@ static void alter_usermode_mapping(struct gk20a *g,
{ {
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
struct vm_area_struct *vma = priv->usermode_vma.vma; struct vm_area_struct *vma = priv->usermode_vma.vma;
bool vma_mapped = priv->usermode_vma.vma_mapped;
u64 addr; u64 addr;
int err; int err;
@@ -2000,14 +2004,20 @@ static void alter_usermode_mapping(struct gk20a *g,
down_write(&vma->vm_mm->mmap_sem); down_write(&vma->vm_mm->mmap_sem);
if (poweroff) { /*
* This is a no-op for the below cases
* a) poweroff and !vma_mapped - > do nothing as no map exists
* b) !poweroff and vmap_mapped -> do nothing as already mapped
*/
if (poweroff && vma_mapped) {
err = zap_vma_ptes(vma, vma->vm_start, SZ_4K); err = zap_vma_ptes(vma, vma->vm_start, SZ_4K);
if (err == 0) { if (err == 0) {
vma->vm_flags = VM_NONE; vma->vm_flags = VM_NONE;
priv->usermode_vma.vma_mapped = false;
} else { } else {
nvgpu_err(g, "can't remove usermode mapping"); nvgpu_err(g, "can't remove usermode mapping");
} }
} else { } else if (!poweroff && !vma_mapped) {
vma->vm_flags = priv->usermode_vma.flags; vma->vm_flags = priv->usermode_vma.flags;
err = io_remap_pfn_range(vma, vma->vm_start, err = io_remap_pfn_range(vma, vma->vm_start,
addr >> PAGE_SHIFT, addr >> PAGE_SHIFT,
@@ -2015,6 +2025,8 @@ static void alter_usermode_mapping(struct gk20a *g,
if (err != 0) { if (err != 0) {
nvgpu_err(g, "can't restore usermode mapping"); nvgpu_err(g, "can't restore usermode mapping");
vma->vm_flags = VM_NONE; vma->vm_flags = VM_NONE;
} else {
priv->usermode_vma.vma_mapped = true;
} }
} }