[PATCH] drm/vmwgfx: Remove rcu locks from user resources
Maaz Mombasawala (VMware
maazm at fastmail.com
Wed Dec 7 21:33:19 UTC 2022
LGTM.
Reviewed-by: Maaz Mombasawala <mombasawalam at vmware.com>
On 12/7/22 09:29, Zack Rusin wrote:
> From: Zack Rusin <zackr at vmware.com>
>
> User resource lookups used rcu to avoid two extra atomics. Unfortunately
> the rcu paths were buggy and it was easy to make the driver crash by
> submitting command buffers from two different threads. Because the
> lookups never show up in performance profiles replace them with a
> regular spin lock which fixes the races in accesses to those shared
> resources.
>
> Fixes kernel oops'es in IGT's vmwgfx execution_buffer stress test and
> seen crashes with apps using shared resources.
>
> Fixes: e14c02e6b699 ("drm/vmwgfx: Look up objects without taking a reference")
> Signed-off-by: Zack Rusin <zackr at vmware.com>
> ---
> drivers/gpu/drm/vmwgfx/ttm_object.c | 41 +-----
> drivers/gpu/drm/vmwgfx/ttm_object.h | 14 --
> drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 38 -----
> drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 18 +--
> drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 176 +++++++++++------------
> drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 33 -----
> 6 files changed, 87 insertions(+), 233 deletions(-)
>
> diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.c b/drivers/gpu/drm/vmwgfx/ttm_object.c
> index 932b125ebf3d..ddf8373c1d77 100644
> --- a/drivers/gpu/drm/vmwgfx/ttm_object.c
> +++ b/drivers/gpu/drm/vmwgfx/ttm_object.c
> @@ -254,40 +254,6 @@ void ttm_base_object_unref(struct ttm_base_object **p_base)
> kref_put(&base->refcount, ttm_release_base);
> }
>
> -/**
> - * ttm_base_object_noref_lookup - look up a base object without reference
> - * @tfile: The struct ttm_object_file the object is registered with.
> - * @key: The object handle.
> - *
> - * This function looks up a ttm base object and returns a pointer to it
> - * without refcounting the pointer. The returned pointer is only valid
> - * until ttm_base_object_noref_release() is called, and the object
> - * pointed to by the returned pointer may be doomed. Any persistent usage
> - * of the object requires a refcount to be taken using kref_get_unless_zero().
> - * Iff this function returns successfully it needs to be paired with
> - * ttm_base_object_noref_release() and no sleeping- or scheduling functions
> - * may be called inbetween these function callse.
> - *
> - * Return: A pointer to the object if successful or NULL otherwise.
> - */
> -struct ttm_base_object *
> -ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key)
> -{
> - struct vmwgfx_hash_item *hash;
> - int ret;
> -
> - rcu_read_lock();
> - ret = ttm_tfile_find_ref_rcu(tfile, key, &hash);
> - if (ret) {
> - rcu_read_unlock();
> - return NULL;
> - }
> -
> - __release(RCU);
> - return hlist_entry(hash, struct ttm_ref_object, hash)->obj;
> -}
> -EXPORT_SYMBOL(ttm_base_object_noref_lookup);
> -
> struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
> uint64_t key)
> {
> @@ -295,15 +261,16 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
> struct vmwgfx_hash_item *hash;
> int ret;
>
> - rcu_read_lock();
> - ret = ttm_tfile_find_ref_rcu(tfile, key, &hash);
> + spin_lock(&tfile->lock);
> + ret = ttm_tfile_find_ref(tfile, key, &hash);
>
> if (likely(ret == 0)) {
> base = hlist_entry(hash, struct ttm_ref_object, hash)->obj;
> if (!kref_get_unless_zero(&base->refcount))
> base = NULL;
> }
> - rcu_read_unlock();
> + spin_unlock(&tfile->lock);
> +
>
> return base;
> }
> diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.h b/drivers/gpu/drm/vmwgfx/ttm_object.h
> index f0ebbe340ad6..8098a3846bae 100644
> --- a/drivers/gpu/drm/vmwgfx/ttm_object.h
> +++ b/drivers/gpu/drm/vmwgfx/ttm_object.h
> @@ -307,18 +307,4 @@ extern int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
> #define ttm_prime_object_kfree(__obj, __prime) \
> kfree_rcu(__obj, __prime.base.rhead)
>
> -struct ttm_base_object *
> -ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key);
> -
> -/**
> - * ttm_base_object_noref_release - release a base object pointer looked up
> - * without reference
> - *
> - * Releases a base object pointer looked up with ttm_base_object_noref_lookup().
> - */
> -static inline void ttm_base_object_noref_release(void)
> -{
> - __acquire(RCU);
> - rcu_read_unlock();
> -}
> #endif
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
> index d218b15953e0..d579f3eee9af 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
> @@ -715,44 +715,6 @@ int vmw_user_bo_lookup(struct drm_file *filp,
> return 0;
> }
>
> -/**
> - * vmw_user_bo_noref_lookup - Look up a vmw user buffer object without reference
> - * @filp: The TTM object file the handle is registered with.
> - * @handle: The user buffer object handle.
> - *
> - * This function looks up a struct vmw_bo and returns a pointer to the
> - * struct vmw_buffer_object it derives from without refcounting the pointer.
> - * The returned pointer is only valid until vmw_user_bo_noref_release() is
> - * called, and the object pointed to by the returned pointer may be doomed.
> - * Any persistent usage of the object requires a refcount to be taken using
> - * ttm_bo_reference_unless_doomed(). Iff this function returns successfully it
> - * needs to be paired with vmw_user_bo_noref_release() and no sleeping-
> - * or scheduling functions may be called in between these function calls.
> - *
> - * Return: A struct vmw_buffer_object pointer if successful or negative
> - * error pointer on failure.
> - */
> -struct vmw_buffer_object *
> -vmw_user_bo_noref_lookup(struct drm_file *filp, u32 handle)
> -{
> - struct vmw_buffer_object *vmw_bo;
> - struct ttm_buffer_object *bo;
> - struct drm_gem_object *gobj = drm_gem_object_lookup(filp, handle);
> -
> - if (!gobj) {
> - DRM_ERROR("Invalid buffer object handle 0x%08lx.\n",
> - (unsigned long)handle);
> - return ERR_PTR(-ESRCH);
> - }
> - vmw_bo = gem_to_vmw_bo(gobj);
> - bo = ttm_bo_get_unless_zero(&vmw_bo->base);
> - vmw_bo = vmw_buffer_object(bo);
> - drm_gem_object_put(gobj);
> -
> - return vmw_bo;
> -}
> -
> -
> /**
> * vmw_bo_fence_single - Utility function to fence a single TTM buffer
> * object without unreserving it.
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
> index b062b020b378..5acbf5849b27 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
> @@ -830,12 +830,7 @@ extern int vmw_user_resource_lookup_handle(
> uint32_t handle,
> const struct vmw_user_resource_conv *converter,
> struct vmw_resource **p_res);
> -extern struct vmw_resource *
> -vmw_user_resource_noref_lookup_handle(struct vmw_private *dev_priv,
> - struct ttm_object_file *tfile,
> - uint32_t handle,
> - const struct vmw_user_resource_conv *
> - converter);
> +
> 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,
> @@ -874,15 +869,6 @@ static inline bool vmw_resource_mob_attached(const struct vmw_resource *res)
> return !RB_EMPTY_NODE(&res->mob_node);
> }
>
> -/**
> - * vmw_user_resource_noref_release - release a user resource pointer looked up
> - * without reference
> - */
> -static inline void vmw_user_resource_noref_release(void)
> -{
> - ttm_base_object_noref_release();
> -}
> -
> /**
> * Buffer object helper functions - vmwgfx_bo.c
> */
> @@ -934,8 +920,6 @@ extern void vmw_bo_unmap(struct vmw_buffer_object *vbo);
> extern void vmw_bo_move_notify(struct ttm_buffer_object *bo,
> struct ttm_resource *mem);
> extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo);
> -extern struct vmw_buffer_object *
> -vmw_user_bo_noref_lookup(struct drm_file *filp, u32 handle);
>
> /**
> * vmw_bo_adjust_prio - Adjust the buffer object eviction priority
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
> index f16fc489d725..dc4a38f9e419 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
> @@ -290,20 +290,26 @@ static void vmw_execbuf_rcache_update(struct vmw_res_cache_entry *rcache,
> rcache->valid_handle = 0;
> }
>
> +enum vmw_val_add_flags {
> + vmw_val_add_flag_none = 0,
> + vmw_val_add_flag_noctx = 1 << 0,
> +};
> +
> /**
> - * vmw_execbuf_res_noref_val_add - Add a resource described by an unreferenced
> - * rcu-protected pointer to the validation list.
> + * vmw_execbuf_res_val_add - Add a resource to the validation list.
> *
> * @sw_context: Pointer to the software context.
> * @res: Unreferenced rcu-protected pointer to the resource.
> * @dirty: Whether to change dirty status.
> + * @flags: specifies whether to use the context or not
> *
> * Returns: 0 on success. Negative error code on failure. Typical error codes
> * are %-EINVAL on inconsistency and %-ESRCH if the resource was doomed.
> */
> -static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context,
> - struct vmw_resource *res,
> - u32 dirty)
> +static int vmw_execbuf_res_val_add(struct vmw_sw_context *sw_context,
> + struct vmw_resource *res,
> + u32 dirty,
> + u32 flags)
> {
> struct vmw_private *dev_priv = res->dev_priv;
> int ret;
> @@ -318,24 +324,30 @@ static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context,
> if (dirty)
> vmw_validation_res_set_dirty(sw_context->ctx,
> rcache->private, dirty);
> - vmw_user_resource_noref_release();
> return 0;
> }
>
> - priv_size = vmw_execbuf_res_size(dev_priv, res_type);
> - ret = vmw_validation_add_resource(sw_context->ctx, res, priv_size,
> - dirty, (void **)&ctx_info,
> - &first_usage);
> - vmw_user_resource_noref_release();
> - if (ret)
> - return ret;
> + if ((flags & vmw_val_add_flag_noctx) != 0) {
> + ret = vmw_validation_add_resource(sw_context->ctx, res, 0, dirty,
> + (void **)&ctx_info, NULL);
> + if (ret)
> + return ret;
>
> - if (priv_size && first_usage) {
> - ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, res,
> - ctx_info);
> - if (ret) {
> - VMW_DEBUG_USER("Failed first usage context setup.\n");
> + } else {
> + priv_size = vmw_execbuf_res_size(dev_priv, res_type);
> + ret = vmw_validation_add_resource(sw_context->ctx, res, priv_size,
> + dirty, (void **)&ctx_info,
> + &first_usage);
> + if (ret)
> return ret;
> +
> + if (priv_size && first_usage) {
> + ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, res,
> + ctx_info);
> + if (ret) {
> + VMW_DEBUG_USER("Failed first usage context setup.\n");
> + return ret;
> + }
> }
> }
>
> @@ -343,43 +355,6 @@ static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context,
> return 0;
> }
>
> -/**
> - * vmw_execbuf_res_noctx_val_add - Add a non-context resource to the resource
> - * validation list if it's not already on it
> - *
> - * @sw_context: Pointer to the software context.
> - * @res: Pointer to the resource.
> - * @dirty: Whether to change dirty status.
> - *
> - * Returns: Zero on success. Negative error code on failure.
> - */
> -static int vmw_execbuf_res_noctx_val_add(struct vmw_sw_context *sw_context,
> - struct vmw_resource *res,
> - u32 dirty)
> -{
> - struct vmw_res_cache_entry *rcache;
> - enum vmw_res_type res_type = vmw_res_type(res);
> - void *ptr;
> - int ret;
> -
> - rcache = &sw_context->res_cache[res_type];
> - if (likely(rcache->valid && rcache->res == res)) {
> - if (dirty)
> - vmw_validation_res_set_dirty(sw_context->ctx,
> - rcache->private, dirty);
> - return 0;
> - }
> -
> - ret = vmw_validation_add_resource(sw_context->ctx, res, 0, dirty,
> - &ptr, NULL);
> - if (ret)
> - return ret;
> -
> - vmw_execbuf_rcache_update(rcache, res, ptr);
> -
> - return 0;
> -}
> -
> /**
> * vmw_view_res_val_add - Add a view and the surface it's pointing to to the
> * validation list
> @@ -398,13 +373,13 @@ static int vmw_view_res_val_add(struct vmw_sw_context *sw_context,
> * First add the resource the view is pointing to, otherwise it may be
> * swapped out when the view is validated.
> */
> - ret = vmw_execbuf_res_noctx_val_add(sw_context, vmw_view_srf(view),
> - vmw_view_dirtying(view));
> + ret = vmw_execbuf_res_val_add(sw_context, vmw_view_srf(view),
> + vmw_view_dirtying(view), vmw_val_add_flag_noctx);
> if (ret)
> return ret;
>
> - return vmw_execbuf_res_noctx_val_add(sw_context, view,
> - VMW_RES_DIRTY_NONE);
> + return vmw_execbuf_res_val_add(sw_context, view, VMW_RES_DIRTY_NONE,
> + vmw_val_add_flag_noctx);
> }
>
> /**
> @@ -475,8 +450,9 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv,
> if (IS_ERR(res))
> continue;
>
> - ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
> - VMW_RES_DIRTY_SET);
> + ret = vmw_execbuf_res_val_add(sw_context, res,
> + VMW_RES_DIRTY_SET,
> + vmw_val_add_flag_noctx);
> if (unlikely(ret != 0))
> return ret;
> }
> @@ -490,9 +466,9 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv,
> if (vmw_res_type(entry->res) == vmw_res_view)
> ret = vmw_view_res_val_add(sw_context, entry->res);
> else
> - ret = vmw_execbuf_res_noctx_val_add
> - (sw_context, entry->res,
> - vmw_binding_dirtying(entry->bt));
> + ret = vmw_execbuf_res_val_add(sw_context, entry->res,
> + vmw_binding_dirtying(entry->bt),
> + vmw_val_add_flag_noctx);
> if (unlikely(ret != 0))
> break;
> }
> @@ -658,7 +634,8 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
> {
> struct vmw_res_cache_entry *rcache = &sw_context->res_cache[res_type];
> struct vmw_resource *res;
> - int ret;
> + int ret = 0;
> + bool needs_unref = false;
>
> if (p_res)
> *p_res = NULL;
> @@ -683,17 +660,18 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
> if (ret)
> return ret;
>
> - res = vmw_user_resource_noref_lookup_handle
> - (dev_priv, sw_context->fp->tfile, *id_loc, converter);
> - if (IS_ERR(res)) {
> + ret = vmw_user_resource_lookup_handle
> + (dev_priv, sw_context->fp->tfile, *id_loc, converter, &res);
> + if (ret != 0) {
> VMW_DEBUG_USER("Could not find/use resource 0x%08x.\n",
> (unsigned int) *id_loc);
> - return PTR_ERR(res);
> + return ret;
> }
> + needs_unref = true;
>
> - ret = vmw_execbuf_res_noref_val_add(sw_context, res, dirty);
> + ret = vmw_execbuf_res_val_add(sw_context, res, dirty, vmw_val_add_flag_none);
> if (unlikely(ret != 0))
> - return ret;
> + goto res_check_done;
>
> if (rcache->valid && rcache->res == res) {
> rcache->valid_handle = true;
> @@ -708,7 +686,11 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
> if (p_res)
> *p_res = res;
>
> - return 0;
> +res_check_done:
> + if (needs_unref)
> + vmw_resource_unreference(&res);
> +
> + return ret;
> }
>
> /**
> @@ -1171,9 +1153,9 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
> int ret;
>
> vmw_validation_preload_bo(sw_context->ctx);
> - vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle);
> - if (IS_ERR(vmw_bo)) {
> - VMW_DEBUG_USER("Could not find or use MOB buffer.\n");
> + ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo);
> + if (ret != 0) {
> + drm_dbg(&dev_priv->drm, "Could not find or use MOB buffer.\n");
> return PTR_ERR(vmw_bo);
> }
> ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, true, false);
> @@ -1225,9 +1207,9 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
> int ret;
>
> vmw_validation_preload_bo(sw_context->ctx);
> - vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle);
> - if (IS_ERR(vmw_bo)) {
> - VMW_DEBUG_USER("Could not find or use GMR region.\n");
> + ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo);
> + if (ret != 0) {
> + drm_dbg(&dev_priv->drm, "Could not find or use GMR region.\n");
> return PTR_ERR(vmw_bo);
> }
> ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, false, false);
> @@ -2025,8 +2007,9 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,
> res = vmw_shader_lookup(vmw_context_res_man(ctx),
> cmd->body.shid, cmd->body.type);
> if (!IS_ERR(res)) {
> - ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
> - VMW_RES_DIRTY_NONE);
> + ret = vmw_execbuf_res_val_add(sw_context, res,
> + VMW_RES_DIRTY_NONE,
> + vmw_val_add_flag_noctx);
> if (unlikely(ret != 0))
> return ret;
>
> @@ -2273,8 +2256,9 @@ static int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv,
> return PTR_ERR(res);
> }
>
> - ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
> - VMW_RES_DIRTY_NONE);
> + ret = vmw_execbuf_res_val_add(sw_context, res,
> + VMW_RES_DIRTY_NONE,
> + vmw_val_add_flag_noctx);
> if (ret)
> return ret;
> }
> @@ -2777,8 +2761,8 @@ static int vmw_cmd_dx_bind_shader(struct vmw_private *dev_priv,
> return PTR_ERR(res);
> }
>
> - ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
> - VMW_RES_DIRTY_NONE);
> + ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
> + vmw_val_add_flag_noctx);
> if (ret) {
> VMW_DEBUG_USER("Error creating resource validation node.\n");
> return ret;
> @@ -3098,8 +3082,8 @@ static int vmw_cmd_dx_bind_streamoutput(struct vmw_private *dev_priv,
>
> vmw_dx_streamoutput_set_size(res, cmd->body.sizeInBytes);
>
> - ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
> - VMW_RES_DIRTY_NONE);
> + ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
> + vmw_val_add_flag_noctx);
> if (ret) {
> DRM_ERROR("Error creating resource validation node.\n");
> return ret;
> @@ -3148,8 +3132,8 @@ static int vmw_cmd_dx_set_streamoutput(struct vmw_private *dev_priv,
> return 0;
> }
>
> - ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
> - VMW_RES_DIRTY_NONE);
> + ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
> + vmw_val_add_flag_noctx);
> if (ret) {
> DRM_ERROR("Error creating resource validation node.\n");
> return ret;
> @@ -4066,22 +4050,26 @@ static int vmw_execbuf_tie_context(struct vmw_private *dev_priv,
> if (ret)
> return ret;
>
> - res = vmw_user_resource_noref_lookup_handle
> + ret = vmw_user_resource_lookup_handle
> (dev_priv, sw_context->fp->tfile, handle,
> - user_context_converter);
> - if (IS_ERR(res)) {
> + user_context_converter, &res);
> + if (ret != 0) {
> VMW_DEBUG_USER("Could not find or user DX context 0x%08x.\n",
> (unsigned int) handle);
> - return PTR_ERR(res);
> + return ret;
> }
>
> - ret = vmw_execbuf_res_noref_val_add(sw_context, res, VMW_RES_DIRTY_SET);
> - if (unlikely(ret != 0))
> + ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_SET,
> + vmw_val_add_flag_none);
> + if (unlikely(ret != 0)){
> + vmw_resource_unreference(&res);
> return ret;
> + }
>
> sw_context->dx_ctx_node = vmw_execbuf_info_from_res(sw_context, res);
> sw_context->man = vmw_context_res_man(res);
>
> + vmw_resource_unreference(&res);
> return 0;
> }
>
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
> index f66caa540e14..c7d645e5ec7b 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
> @@ -281,39 +281,6 @@ int vmw_user_resource_lookup_handle(struct vmw_private *dev_priv,
> return ret;
> }
>
> -/**
> - * vmw_user_resource_noref_lookup_handle - lookup a struct resource from a
> - * TTM user-space handle and perform basic type checks
> - *
> - * @dev_priv: Pointer to a device private struct
> - * @tfile: Pointer to a struct ttm_object_file identifying the caller
> - * @handle: The TTM user-space handle
> - * @converter: Pointer to an object describing the resource type
> - *
> - * If the handle can't be found or is associated with an incorrect resource
> - * type, -EINVAL will be returned.
> - */
> -struct vmw_resource *
> -vmw_user_resource_noref_lookup_handle(struct vmw_private *dev_priv,
> - struct ttm_object_file *tfile,
> - uint32_t handle,
> - const struct vmw_user_resource_conv
> - *converter)
> -{
> - struct ttm_base_object *base;
> -
> - base = ttm_base_object_noref_lookup(tfile, handle);
> - if (!base)
> - return ERR_PTR(-ESRCH);
> -
> - if (unlikely(ttm_base_object_type(base) != converter->object_type)) {
> - ttm_base_object_noref_release();
> - return ERR_PTR(-EINVAL);
> - }
> -
> - return converter->base_obj_to_res(base);
> -}
> -
> /*
> * Helper function that looks either a surface or bo.
> *
--
Maaz Mombasawala (VMware) <maazm at fastmail.com>
More information about the dri-devel
mailing list