radv/amdgpu: Use reference counting for bos.
authorBas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
Sat, 4 Feb 2017 22:26:50 +0000 (23:26 +0100)
committerBas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
Wed, 29 Mar 2017 06:50:48 +0000 (08:50 +0200)
Per the Vulkan spec, memory objects may be deleted before the buffers
and images using them are deleted, although those resources then
cannot be used except for deletion themselves.

For the virtual buffers, we need to access them on resource destruction
to unmap the regions, so this results in a use-after-free. Implement
reference counting to avoid this.

Signed-off-by: Bas Nieuwenhuizen <basni@google.com>
Reviewed-by: Dave Airlie <airlied@redhat.com>
src/amd/vulkan/winsys/amdgpu/radv_amdgpu_bo.c
src/amd/vulkan/winsys/amdgpu/radv_amdgpu_bo.h

index 8e78ef75233cc4a68b2dd84914c03a7e52d15239..7b679450cbc609c6cc192e59d205937721ca7606 100644 (file)
 #include <amdgpu_drm.h>
 #include <inttypes.h>
 
+#include "util/u_atomic.h"
+
+
+static void radv_amdgpu_winsys_bo_destroy(struct radeon_winsys_bo *_bo);
+
 static void
 radv_amdgpu_winsys_virtual_map(struct radv_amdgpu_winsys_bo *bo,
                                const struct radv_amdgpu_map_range *range)
@@ -43,6 +48,7 @@ radv_amdgpu_winsys_virtual_map(struct radv_amdgpu_winsys_bo *bo,
        if (!range->bo)
                return; /* TODO: PRT mapping */
 
+       p_atomic_inc(&range->bo->ref_count);
        int r = amdgpu_bo_va_op(range->bo->bo, range->bo_offset, range->size,
                                range->offset + bo->va, 0, AMDGPU_VA_OP_MAP);
        if (r)
@@ -62,6 +68,7 @@ radv_amdgpu_winsys_virtual_unmap(struct radv_amdgpu_winsys_bo *bo,
                                range->offset + bo->va, 0, AMDGPU_VA_OP_UNMAP);
        if (r)
                abort();
+       radv_amdgpu_winsys_bo_destroy((struct radeon_winsys_bo *)range->bo);
 }
 
 static void
@@ -212,6 +219,8 @@ static void radv_amdgpu_winsys_bo_destroy(struct radeon_winsys_bo *_bo)
 {
        struct radv_amdgpu_winsys_bo *bo = radv_amdgpu_winsys_bo(_bo);
 
+       if (p_atomic_dec_return(&bo->ref_count))
+               return;
        if (bo->is_virtual) {
                for (uint32_t i = 0; i < bo->range_count; ++i) {
                        radv_amdgpu_winsys_virtual_unmap(bo, bo->ranges + i);
@@ -273,6 +282,7 @@ radv_amdgpu_winsys_bo_create(struct radeon_winsys *_ws,
        bo->size = size;
        bo->ws = ws;
        bo->is_virtual = !!(flags & RADEON_FLAG_VIRTUAL);
+       bo->ref_count = 1;
 
        if (flags & RADEON_FLAG_VIRTUAL) {
                bo->ranges = realloc(NULL, sizeof(struct radv_amdgpu_map_range));
index c7d484bc8dd31ea2fcd8db77182bbc1e012aa51d..4512e76b3339684357ac71e816c0073dd9352a5a 100644 (file)
@@ -45,6 +45,7 @@ struct radv_amdgpu_winsys_bo {
        uint64_t size;
        struct radv_amdgpu_winsys *ws;
        bool is_virtual;
+       int ref_count;
 
        union {
                /* physical bo */