From 64ad2abfe9a628ce79859d072704bd1ef7682044 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 26 Sep 2018 15:59:20 +0200 Subject: [PATCH] drm/vmwgfx: Adapt validation code for reference-free lookups Adapt the validation code so that vmw_validation_add[res|bo] can be called under an rcu read lock (non-sleeping) and with rcu-only protected resource- or buffer object pointers. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_validation.c | 61 ++++++++++++++++++++++++++++-- drivers/gpu/drm/vmwgfx/vmwgfx_validation.h | 19 +++++++++- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c index 3158fe1..184025f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c @@ -94,11 +94,12 @@ struct vmw_validation_res_node { * * Return: Pointer to the allocated memory on success. NULL on failure. */ -void *vmw_validation_mem_alloc(struct vmw_validation_context *ctx, size_t size) +void *vmw_validation_mem_alloc(struct vmw_validation_context *ctx, + unsigned int size) { void *addr; - size = ALIGN(size, sizeof(long)); + size = vmw_validation_align(size); if (size > PAGE_SIZE) return NULL; @@ -262,7 +263,9 @@ int vmw_validation_add_bo(struct vmw_validation_context *ctx, } } val_buf = &bo_node->base; - val_buf->bo = ttm_bo_reference(&vbo->base); + val_buf->bo = ttm_bo_get_unless_zero(&vbo->base); + if (!val_buf->bo) + return -ESRCH; val_buf->shared = false; list_add_tail(&val_buf->head, &ctx->bo_list); bo_node->as_mob = as_mob; @@ -313,7 +316,10 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx, return ret; } } - node->res = vmw_resource_reference(res); + node->res = vmw_resource_reference_unless_doomed(res); + if (!node->res) + return -ESRCH; + node->first_usage = 1; if (!res->dev_priv->has_mob) { list_add_tail(&node->head, &ctx->resource_list); @@ -715,3 +721,50 @@ void vmw_validation_done(struct vmw_validation_context *ctx, mutex_unlock(ctx->res_mutex); vmw_validation_unref_lists(ctx); } + +/** + * vmw_validation_preload_bo - Preload the validation memory allocator for a + * call to vmw_validation_add_bo(). + * @ctx: Pointer to the validation context. + * + * Iff this function returns successfully, the next call to + * vmw_validation_add_bo() is guaranteed not to sleep. An error is not fatal + * but voids the guarantee. + * + * Returns: Zero if successful, %-EINVAL otherwise. + */ +int vmw_validation_preload_bo(struct vmw_validation_context *ctx) +{ + unsigned int size = sizeof(struct vmw_validation_bo_node); + + if (!vmw_validation_mem_alloc(ctx, size)) + return -ENOMEM; + + ctx->mem_size_left += size; + return 0; +} + +/** + * vmw_validation_preload_res - Preload the validation memory allocator for a + * call to vmw_validation_add_res(). + * @ctx: Pointer to the validation context. + * @size: Size of the validation node extra data. See below. + * + * Iff this function returns successfully, the next call to + * vmw_validation_add_res() with the same or smaller @size is guaranteed not to + * sleep. An error is not fatal but voids the guarantee. + * + * Returns: Zero if successful, %-EINVAL otherwise. + */ +int vmw_validation_preload_res(struct vmw_validation_context *ctx, + unsigned int size) +{ + size = vmw_validation_align(sizeof(struct vmw_validation_res_node) + + size) + + vmw_validation_align(sizeof(struct vmw_validation_bo_node)); + if (!vmw_validation_mem_alloc(ctx, size)) + return -ENOMEM; + + ctx->mem_size_left += size; + return 0; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h index 0eb2d02..b57e329 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h @@ -177,6 +177,18 @@ vmw_validation_context_init(struct vmw_validation_context *ctx) INIT_LIST_HEAD(&ctx->bo_list); } +/** + * vmw_validation_align - Align a validation memory allocation + * @val: The size to be aligned + * + * Returns: @val aligned to the granularity used by the validation memory + * allocator. + */ +static inline unsigned int vmw_validation_align(unsigned int val) +{ + return ALIGN(val, sizeof(long)); +} + int vmw_validation_add_bo(struct vmw_validation_context *ctx, struct vmw_buffer_object *vbo, bool as_mob, bool cpu_blit); @@ -207,6 +219,9 @@ void vmw_validation_revert(struct vmw_validation_context *ctx); void vmw_validation_done(struct vmw_validation_context *ctx, struct vmw_fence_obj *fence); -void *vmw_validation_mem_alloc(struct vmw_validation_context *ctx, size_t size); - +void *vmw_validation_mem_alloc(struct vmw_validation_context *ctx, + unsigned int size); +int vmw_validation_preload_bo(struct vmw_validation_context *ctx); +int vmw_validation_preload_res(struct vmw_validation_context *ctx, + unsigned int size); #endif -- 2.7.4