diff mbox

[3.16.y-ckt,stable] Patch "drm/vmwgfx: Fix up user_dmabuf refcounting" has been added to staging queue

Message ID 1445894042-31468-1-git-send-email-kamal@canonical.com
State New
Headers show

Commit Message

Kamal Mostafa Oct. 26, 2015, 9:14 p.m. UTC
This is a note to let you know that I have just added a patch titled

    drm/vmwgfx: Fix up user_dmabuf refcounting

to the linux-3.16.y-queue branch of the 3.16.y-ckt extended stable tree 
which can be found at:

    http://kernel.ubuntu.com/git/ubuntu/linux.git/log/?h=linux-3.16.y-queue

This patch is scheduled to be released in version 3.19.8-ckt9.

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.16.y-ckt tree, see
https://wiki.ubuntu.com/Kernel/Dev/ExtendedStable

Thanks.
-Kamal

------

From 127037ecff9d5e99fbc0c5405cb863dca04b9df7 Mon Sep 17 00:00:00 2001
From: Thomas Hellstrom <thellstrom@vmware.com>
Date: Mon, 14 Sep 2015 01:13:11 -0700
Subject: drm/vmwgfx: Fix up user_dmabuf refcounting

commit 54c12bc374408faddbff75dbf1a6167c19af39c4 upstream.

If user space calls unreference on a user_dmabuf it will typically
kill the struct ttm_base_object member which is responsible for the
user-space visibility. However the dmabuf part may still be alive and
refcounted. In some situations, like for shared guest-backed surface
referencing/opening, the driver may try to reference the
struct ttm_base_object member again, causing an immediate kernel warning
and a later kernel NULL pointer dereference.

Fix this by always maintaining a reference on the struct
ttm_base_object member, in situations where it might subsequently be
referenced.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.h      |  6 ++++--
 drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c  |  6 ++++--
 drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c  |  2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 29 +++++++++++++++++++++--------
 drivers/gpu/drm/vmwgfx/vmwgfx_shader.c   |  2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_surface.c  | 11 ++++++++---
 6 files changed, 39 insertions(+), 17 deletions(-)

--
1.9.1

Comments

Thomas Hellstrom Oct. 28, 2015, 6:59 a.m. UTC | #1
Kamal,

On 10/26/2015 10:14 PM, Kamal Mostafa wrote:
> This is a note to let you know that I have just added a patch titled
>
>     drm/vmwgfx: Fix up user_dmabuf refcounting
>
> to the linux-3.16.y-queue branch of the 3.16.y-ckt extended stable tree 
> which can be found at:
>
>     https://urldefense.proofpoint.com/v2/url?u=http-3A__kernel.ubuntu.com_git_ubuntu_linux.git_log_-3Fh-3Dlinux-2D3.16.y-2Dqueue&d=BQIBAg&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=vpukPkBtpoNQp2IUKuFviOmPNYWVKmen3Jeeu55zmEA&m=isTitca95-By_EWSOxPnvLlaknByRjOoT7RUZIGf6qQ&s=TQTzdLueIXiKqaE8RiMOb_93cZMeCteUK1NObANnsFk&e= 

Unfortunately there was a regression introduced with this patch. The fix
for the regression is tiny and introduced upstream with patch
ed7d78b2da32198ca4c70172e3b63c6b3e2c570b, "drm/vmwgfx: Fix kernel NULL
pointer dereference on older hardware", also CC'd stable.
Please, if possible, make sure both these patches are pushed at the same
time.



>
> This patch is scheduled to be released in version 3.19.8-ckt9.
>
> If you, or anyone else, feels it should not be added to this tree, please 
> reply to this email.
>
> For more information about the 3.16.y-ckt tree, see
> https://urldefense.proofpoint.com/v2/url?u=https-3A__wiki.ubuntu.com_Kernel_Dev_ExtendedStable&d=BQIBAg&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=vpukPkBtpoNQp2IUKuFviOmPNYWVKmen3Jeeu55zmEA&m=isTitca95-By_EWSOxPnvLlaknByRjOoT7RUZIGf6qQ&s=UpPaE-obh_ulxo23i6417ysrWYr8XKtmGEnXV2ts5P0&e= 
>
> Thanks.
> -Kamal
>
> ------
>
> From 127037ecff9d5e99fbc0c5405cb863dca04b9df7 Mon Sep 17 00:00:00 2001
> From: Thomas Hellstrom <thellstrom@vmware.com>
> Date: Mon, 14 Sep 2015 01:13:11 -0700
> Subject: drm/vmwgfx: Fix up user_dmabuf refcounting
>
> commit 54c12bc374408faddbff75dbf1a6167c19af39c4 upstream.
>
> If user space calls unreference on a user_dmabuf it will typically
> kill the struct ttm_base_object member which is responsible for the
> user-space visibility. However the dmabuf part may still be alive and
> refcounted. In some situations, like for shared guest-backed surface
> referencing/opening, the driver may try to reference the
> struct ttm_base_object member again, causing an immediate kernel warning
> and a later kernel NULL pointer dereference.
>
> Fix this by always maintaining a reference on the struct
> ttm_base_object member, in situations where it might subsequently be
> referenced.
>
> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
> Reviewed-by: Brian Paul <brianp@vmware.com>
> Reviewed-by: Sinclair Yeh <syeh@vmware.com>
> Signed-off-by: Kamal Mostafa <kamal@canonical.com>
> ---
>  drivers/gpu/drm/vmwgfx/vmwgfx_drv.h      |  6 ++++--
>  drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c  |  6 ++++--
>  drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c  |  2 +-
>  drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 29 +++++++++++++++++++++--------
>  drivers/gpu/drm/vmwgfx/vmwgfx_shader.c   |  2 +-
>  drivers/gpu/drm/vmwgfx/vmwgfx_surface.c  | 11 ++++++++---
>  6 files changed, 39 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
> index d26a6da..d8896ed 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
> @@ -636,7 +636,8 @@ extern int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv,
>  				 uint32_t size,
>  				 bool shareable,
>  				 uint32_t *handle,
> -				 struct vmw_dma_buffer **p_dma_buf);
> +				 struct vmw_dma_buffer **p_dma_buf,
> +				 struct ttm_base_object **p_base);
>  extern int vmw_user_dmabuf_reference(struct ttm_object_file *tfile,
>  				     struct vmw_dma_buffer *dma_buf,
>  				     uint32_t *handle);
> @@ -650,7 +651,8 @@ extern uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo,
>  					 uint32_t cur_validate_node);
>  extern void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo);
>  extern int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
> -				  uint32_t id, struct vmw_dma_buffer **out);
> +				  uint32_t id, struct vmw_dma_buffer **out,
> +				  struct ttm_base_object **base);
>  extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
>  				  struct drm_file *file_priv);
>  extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
> index 2711b09..01b8423 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
> @@ -887,7 +887,8 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
>  	struct vmw_relocation *reloc;
>  	int ret;
>
> -	ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
> +	ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo,
> +				     NULL);
>  	if (unlikely(ret != 0)) {
>  		DRM_ERROR("Could not find or use MOB buffer.\n");
>  		return -EINVAL;
> @@ -948,7 +949,8 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
>  	struct vmw_relocation *reloc;
>  	int ret;
>
> -	ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
> +	ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo,
> +				     NULL);
>  	if (unlikely(ret != 0)) {
>  		DRM_ERROR("Could not find or use GMR region.\n");
>  		return -EINVAL;
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
> index 87e39f6..e189898 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
> @@ -484,7 +484,7 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data,
>  		goto out_unlock;
>  	}
>
> -	ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &buf);
> +	ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &buf, NULL);
>  	if (ret)
>  		goto out_unlock;
>
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
> index 210ef15..c5b4c47 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
> @@ -356,7 +356,7 @@ int vmw_user_lookup_handle(struct vmw_private *dev_priv,
>  	}
>
>  	*out_surf = NULL;
> -	ret = vmw_user_dmabuf_lookup(tfile, handle, out_buf);
> +	ret = vmw_user_dmabuf_lookup(tfile, handle, out_buf, NULL);
>  	return ret;
>  }
>
> @@ -483,7 +483,8 @@ int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv,
>  			  uint32_t size,
>  			  bool shareable,
>  			  uint32_t *handle,
> -			  struct vmw_dma_buffer **p_dma_buf)
> +			  struct vmw_dma_buffer **p_dma_buf,
> +			  struct ttm_base_object **p_base)
>  {
>  	struct vmw_user_dma_buffer *user_bo;
>  	struct ttm_buffer_object *tmp;
> @@ -517,6 +518,10 @@ int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv,
>  	}
>
>  	*p_dma_buf = &user_bo->dma;
> +	if (p_base) {
> +		*p_base = &user_bo->prime.base;
> +		kref_get(&(*p_base)->refcount);
> +	}
>  	*handle = user_bo->prime.base.hash.key;
>
>  out_no_base_object:
> @@ -633,6 +638,7 @@ int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data,
>  	struct vmw_dma_buffer *dma_buf;
>  	struct vmw_user_dma_buffer *user_bo;
>  	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
> +	struct ttm_base_object *buffer_base;
>  	int ret;
>
>  	if ((arg->flags & (drm_vmw_synccpu_read | drm_vmw_synccpu_write)) == 0
> @@ -645,7 +651,8 @@ int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data,
>
>  	switch (arg->op) {
>  	case drm_vmw_synccpu_grab:
> -		ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &dma_buf);
> +		ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &dma_buf,
> +					     &buffer_base);
>  		if (unlikely(ret != 0))
>  			return ret;
>
> @@ -653,6 +660,7 @@ int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data,
>  				       dma);
>  		ret = vmw_user_dmabuf_synccpu_grab(user_bo, tfile, arg->flags);
>  		vmw_dmabuf_unreference(&dma_buf);
> +		ttm_base_object_unref(&buffer_base);
>  		if (unlikely(ret != 0 && ret != -ERESTARTSYS &&
>  			     ret != -EBUSY)) {
>  			DRM_ERROR("Failed synccpu grab on handle 0x%08x.\n",
> @@ -694,7 +702,8 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
>  		return ret;
>
>  	ret = vmw_user_dmabuf_alloc(dev_priv, vmw_fpriv(file_priv)->tfile,
> -				    req->size, false, &handle, &dma_buf);
> +				    req->size, false, &handle, &dma_buf,
> +				    NULL);
>  	if (unlikely(ret != 0))
>  		goto out_no_dmabuf;
>
> @@ -723,7 +732,8 @@ int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data,
>  }
>
>  int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
> -			   uint32_t handle, struct vmw_dma_buffer **out)
> +			   uint32_t handle, struct vmw_dma_buffer **out,
> +			   struct ttm_base_object **p_base)
>  {
>  	struct vmw_user_dma_buffer *vmw_user_bo;
>  	struct ttm_base_object *base;
> @@ -745,7 +755,10 @@ int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
>  	vmw_user_bo = container_of(base, struct vmw_user_dma_buffer,
>  				   prime.base);
>  	(void)ttm_bo_reference(&vmw_user_bo->dma.base);
> -	ttm_base_object_unref(&base);
> +	if (p_base)
> +		*p_base = base;
> +	else
> +		ttm_base_object_unref(&base);
>  	*out = &vmw_user_bo->dma;
>
>  	return 0;
> @@ -1006,7 +1019,7 @@ int vmw_dumb_create(struct drm_file *file_priv,
>
>  	ret = vmw_user_dmabuf_alloc(dev_priv, vmw_fpriv(file_priv)->tfile,
>  				    args->size, false, &args->handle,
> -				    &dma_buf);
> +				    &dma_buf, NULL);
>  	if (unlikely(ret != 0))
>  		goto out_no_dmabuf;
>
> @@ -1034,7 +1047,7 @@ int vmw_dumb_map_offset(struct drm_file *file_priv,
>  	struct vmw_dma_buffer *out_buf;
>  	int ret;
>
> -	ret = vmw_user_dmabuf_lookup(tfile, handle, &out_buf);
> +	ret = vmw_user_dmabuf_lookup(tfile, handle, &out_buf, NULL);
>  	if (ret != 0)
>  		return -EINVAL;
>
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
> index 6a4584a..d2751ad 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
> @@ -470,7 +470,7 @@ int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
>
>  	if (arg->buffer_handle != SVGA3D_INVALID_ID) {
>  		ret = vmw_user_dmabuf_lookup(tfile, arg->buffer_handle,
> -					     &buffer);
> +					     &buffer, NULL);
>  		if (unlikely(ret != 0)) {
>  			DRM_ERROR("Could not find buffer for shader "
>  				  "creation.\n");
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
> index 4ecdbf3..9e190db6 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
> @@ -43,6 +43,7 @@ struct vmw_user_surface {
>  	struct vmw_surface srf;
>  	uint32_t size;
>  	struct drm_master *master;
> +	struct ttm_base_object *backup_base;
>  };
>
>  /**
> @@ -652,6 +653,7 @@ static void vmw_user_surface_base_release(struct ttm_base_object **p_base)
>  	struct vmw_resource *res = &user_srf->srf.res;
>
>  	*p_base = NULL;
> +	ttm_base_object_unref(&user_srf->backup_base);
>  	vmw_resource_unreference(&res);
>  }
>
> @@ -846,7 +848,8 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
>  					    res->backup_size,
>  					    true,
>  					    &backup_handle,
> -					    &res->backup);
> +					    &res->backup,
> +					    &user_srf->backup_base);
>  		if (unlikely(ret != 0)) {
>  			vmw_resource_unreference(&res);
>  			goto out_unlock;
> @@ -1309,7 +1312,8 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
>
>  	if (req->buffer_handle != SVGA3D_INVALID_ID) {
>  		ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle,
> -					     &res->backup);
> +					     &res->backup,
> +					     &user_srf->backup_base);
>  	} else if (req->drm_surface_flags &
>  		   drm_vmw_surface_flag_create_buffer)
>  		ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
> @@ -1317,7 +1321,8 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
>  					    req->drm_surface_flags &
>  					    drm_vmw_surface_flag_shareable,
>  					    &backup_handle,
> -					    &res->backup);
> +					    &res->backup,
> +					    &user_srf->backup_base);
>
>  	if (unlikely(ret != 0)) {
>  		vmw_resource_unreference(&res);
> --
> 1.9.1
>
diff mbox

Patch

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index d26a6da..d8896ed 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -636,7 +636,8 @@  extern int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv,
 				 uint32_t size,
 				 bool shareable,
 				 uint32_t *handle,
-				 struct vmw_dma_buffer **p_dma_buf);
+				 struct vmw_dma_buffer **p_dma_buf,
+				 struct ttm_base_object **p_base);
 extern int vmw_user_dmabuf_reference(struct ttm_object_file *tfile,
 				     struct vmw_dma_buffer *dma_buf,
 				     uint32_t *handle);
@@ -650,7 +651,8 @@  extern uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo,
 					 uint32_t cur_validate_node);
 extern void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo);
 extern int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
-				  uint32_t id, struct vmw_dma_buffer **out);
+				  uint32_t id, struct vmw_dma_buffer **out,
+				  struct ttm_base_object **base);
 extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
 				  struct drm_file *file_priv);
 extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 2711b09..01b8423 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -887,7 +887,8 @@  static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
 	struct vmw_relocation *reloc;
 	int ret;

-	ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
+	ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo,
+				     NULL);
 	if (unlikely(ret != 0)) {
 		DRM_ERROR("Could not find or use MOB buffer.\n");
 		return -EINVAL;
@@ -948,7 +949,8 @@  static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
 	struct vmw_relocation *reloc;
 	int ret;

-	ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
+	ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo,
+				     NULL);
 	if (unlikely(ret != 0)) {
 		DRM_ERROR("Could not find or use GMR region.\n");
 		return -EINVAL;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
index 87e39f6..e189898 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
@@ -484,7 +484,7 @@  int vmw_overlay_ioctl(struct drm_device *dev, void *data,
 		goto out_unlock;
 	}

-	ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &buf);
+	ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &buf, NULL);
 	if (ret)
 		goto out_unlock;

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 210ef15..c5b4c47 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -356,7 +356,7 @@  int vmw_user_lookup_handle(struct vmw_private *dev_priv,
 	}

 	*out_surf = NULL;
-	ret = vmw_user_dmabuf_lookup(tfile, handle, out_buf);
+	ret = vmw_user_dmabuf_lookup(tfile, handle, out_buf, NULL);
 	return ret;
 }

@@ -483,7 +483,8 @@  int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv,
 			  uint32_t size,
 			  bool shareable,
 			  uint32_t *handle,
-			  struct vmw_dma_buffer **p_dma_buf)
+			  struct vmw_dma_buffer **p_dma_buf,
+			  struct ttm_base_object **p_base)
 {
 	struct vmw_user_dma_buffer *user_bo;
 	struct ttm_buffer_object *tmp;
@@ -517,6 +518,10 @@  int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv,
 	}

 	*p_dma_buf = &user_bo->dma;
+	if (p_base) {
+		*p_base = &user_bo->prime.base;
+		kref_get(&(*p_base)->refcount);
+	}
 	*handle = user_bo->prime.base.hash.key;

 out_no_base_object:
@@ -633,6 +638,7 @@  int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data,
 	struct vmw_dma_buffer *dma_buf;
 	struct vmw_user_dma_buffer *user_bo;
 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+	struct ttm_base_object *buffer_base;
 	int ret;

 	if ((arg->flags & (drm_vmw_synccpu_read | drm_vmw_synccpu_write)) == 0
@@ -645,7 +651,8 @@  int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data,

 	switch (arg->op) {
 	case drm_vmw_synccpu_grab:
-		ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &dma_buf);
+		ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &dma_buf,
+					     &buffer_base);
 		if (unlikely(ret != 0))
 			return ret;

@@ -653,6 +660,7 @@  int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data,
 				       dma);
 		ret = vmw_user_dmabuf_synccpu_grab(user_bo, tfile, arg->flags);
 		vmw_dmabuf_unreference(&dma_buf);
+		ttm_base_object_unref(&buffer_base);
 		if (unlikely(ret != 0 && ret != -ERESTARTSYS &&
 			     ret != -EBUSY)) {
 			DRM_ERROR("Failed synccpu grab on handle 0x%08x.\n",
@@ -694,7 +702,8 @@  int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
 		return ret;

 	ret = vmw_user_dmabuf_alloc(dev_priv, vmw_fpriv(file_priv)->tfile,
-				    req->size, false, &handle, &dma_buf);
+				    req->size, false, &handle, &dma_buf,
+				    NULL);
 	if (unlikely(ret != 0))
 		goto out_no_dmabuf;

@@ -723,7 +732,8 @@  int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data,
 }

 int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
-			   uint32_t handle, struct vmw_dma_buffer **out)
+			   uint32_t handle, struct vmw_dma_buffer **out,
+			   struct ttm_base_object **p_base)
 {
 	struct vmw_user_dma_buffer *vmw_user_bo;
 	struct ttm_base_object *base;
@@ -745,7 +755,10 @@  int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
 	vmw_user_bo = container_of(base, struct vmw_user_dma_buffer,
 				   prime.base);
 	(void)ttm_bo_reference(&vmw_user_bo->dma.base);
-	ttm_base_object_unref(&base);
+	if (p_base)
+		*p_base = base;
+	else
+		ttm_base_object_unref(&base);
 	*out = &vmw_user_bo->dma;

 	return 0;
@@ -1006,7 +1019,7 @@  int vmw_dumb_create(struct drm_file *file_priv,

 	ret = vmw_user_dmabuf_alloc(dev_priv, vmw_fpriv(file_priv)->tfile,
 				    args->size, false, &args->handle,
-				    &dma_buf);
+				    &dma_buf, NULL);
 	if (unlikely(ret != 0))
 		goto out_no_dmabuf;

@@ -1034,7 +1047,7 @@  int vmw_dumb_map_offset(struct drm_file *file_priv,
 	struct vmw_dma_buffer *out_buf;
 	int ret;

-	ret = vmw_user_dmabuf_lookup(tfile, handle, &out_buf);
+	ret = vmw_user_dmabuf_lookup(tfile, handle, &out_buf, NULL);
 	if (ret != 0)
 		return -EINVAL;

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
index 6a4584a..d2751ad 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
@@ -470,7 +470,7 @@  int vmw_shader_define_ioctl(struct drm_device *dev, void *data,

 	if (arg->buffer_handle != SVGA3D_INVALID_ID) {
 		ret = vmw_user_dmabuf_lookup(tfile, arg->buffer_handle,
-					     &buffer);
+					     &buffer, NULL);
 		if (unlikely(ret != 0)) {
 			DRM_ERROR("Could not find buffer for shader "
 				  "creation.\n");
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index 4ecdbf3..9e190db6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -43,6 +43,7 @@  struct vmw_user_surface {
 	struct vmw_surface srf;
 	uint32_t size;
 	struct drm_master *master;
+	struct ttm_base_object *backup_base;
 };

 /**
@@ -652,6 +653,7 @@  static void vmw_user_surface_base_release(struct ttm_base_object **p_base)
 	struct vmw_resource *res = &user_srf->srf.res;

 	*p_base = NULL;
+	ttm_base_object_unref(&user_srf->backup_base);
 	vmw_resource_unreference(&res);
 }

@@ -846,7 +848,8 @@  int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
 					    res->backup_size,
 					    true,
 					    &backup_handle,
-					    &res->backup);
+					    &res->backup,
+					    &user_srf->backup_base);
 		if (unlikely(ret != 0)) {
 			vmw_resource_unreference(&res);
 			goto out_unlock;
@@ -1309,7 +1312,8 @@  int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,

 	if (req->buffer_handle != SVGA3D_INVALID_ID) {
 		ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle,
-					     &res->backup);
+					     &res->backup,
+					     &user_srf->backup_base);
 	} else if (req->drm_surface_flags &
 		   drm_vmw_surface_flag_create_buffer)
 		ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
@@ -1317,7 +1321,8 @@  int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
 					    req->drm_surface_flags &
 					    drm_vmw_surface_flag_shareable,
 					    &backup_handle,
-					    &res->backup);
+					    &res->backup,
+					    &user_srf->backup_base);

 	if (unlikely(ret != 0)) {
 		vmw_resource_unreference(&res);