summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2019-11-13 14:56:12 +0100
committerGerd Hoffmann <kraxel@redhat.com>2019-11-15 08:00:08 +0100
commit9786b65bc61acec63f923978c75e707afbb74bc7 (patch)
treeb27b7b08da561cec118a2f326de7b426ee487ac7
parenta64fc11b9a520c55ca34d82e5ca32274f49b6b15 (diff)
drm/ttm: fix mmap refcountingdrm-misc-next-fixes-2019-11-20
When mapping ttm objects via drm_gem_ttm_mmap() helper drm_gem_mmap_obj() will take an object reference. That gets never released due to ttm having its own reference counting. Fix that by dropping the gem object reference once the ttm mmap completed (and ttm refcount got bumped). For that to work properly the drm_gem_object_get() call in drm_gem_ttm_mmap() must be moved so it happens before calling obj->funcs->mmap(), otherwise the gem refcount would go down to zero. Fixes: 231927d939f0 ("drm/ttm: add drm_gem_ttm_mmap()") Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Tested-by: Thomas Zimmermann <tzimmermann@suse.de> Link: http://patchwork.freedesktop.org/patch/msgid/20191113135612.19679-1-kraxel@redhat.com
-rw-r--r--drivers/gpu/drm/drm_gem.c24
-rw-r--r--drivers/gpu/drm/drm_gem_ttm_helper.c13
2 files changed, 26 insertions, 11 deletions
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 2f2b889096b0..000fa4a1899f 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1105,21 +1105,33 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
if (obj_size < vma->vm_end - vma->vm_start)
return -EINVAL;
+ /* Take a ref for this mapping of the object, so that the fault
+ * handler can dereference the mmap offset's pointer to the object.
+ * This reference is cleaned up by the corresponding vm_close
+ * (which should happen whether the vma was created by this call, or
+ * by a vm_open due to mremap or partial unmap or whatever).
+ */
+ drm_gem_object_get(obj);
+
if (obj->funcs && obj->funcs->mmap) {
/* Remove the fake offset */
vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
ret = obj->funcs->mmap(obj, vma);
- if (ret)
+ if (ret) {
+ drm_gem_object_put_unlocked(obj);
return ret;
+ }
WARN_ON(!(vma->vm_flags & VM_DONTEXPAND));
} else {
if (obj->funcs && obj->funcs->vm_ops)
vma->vm_ops = obj->funcs->vm_ops;
else if (dev->driver->gem_vm_ops)
vma->vm_ops = dev->driver->gem_vm_ops;
- else
+ else {
+ drm_gem_object_put_unlocked(obj);
return -EINVAL;
+ }
vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
@@ -1128,14 +1140,6 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
vma->vm_private_data = obj;
- /* Take a ref for this mapping of the object, so that the fault
- * handler can dereference the mmap offset's pointer to the object.
- * This reference is cleaned up by the corresponding vm_close
- * (which should happen whether the vma was created by this call, or
- * by a vm_open due to mremap or partial unmap or whatever).
- */
- drm_gem_object_get(obj);
-
return 0;
}
EXPORT_SYMBOL(drm_gem_mmap_obj);
diff --git a/drivers/gpu/drm/drm_gem_ttm_helper.c b/drivers/gpu/drm/drm_gem_ttm_helper.c
index 7412bfc5c05a..605a8a3da7f9 100644
--- a/drivers/gpu/drm/drm_gem_ttm_helper.c
+++ b/drivers/gpu/drm/drm_gem_ttm_helper.c
@@ -64,8 +64,19 @@ int drm_gem_ttm_mmap(struct drm_gem_object *gem,
struct vm_area_struct *vma)
{
struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem);
+ int ret;
- return ttm_bo_mmap_obj(vma, bo);
+ ret = ttm_bo_mmap_obj(vma, bo);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * ttm has its own object refcounting, so drop gem reference
+ * to avoid double accounting counting.
+ */
+ drm_gem_object_put_unlocked(gem);
+
+ return 0;
}
EXPORT_SYMBOL(drm_gem_ttm_mmap);