Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/imagination: Break an object reference loop

When remaining resources are being cleaned up on driver close,
outstanding VM mappings may result in resources being leaked, due
to an object reference loop, as shown below, with each object (or
set of objects) referencing the object below it:

PVR GEM Object
GPU scheduler "finished" fence
GPU scheduler “scheduled” fence
PVR driver “done” fence
PVR Context
PVR VM Context
PVR VM Mappings
PVR GEM Object

The reference that the PVR VM Context has on the VM mappings is a
soft one, in the sense that the freeing of outstanding VM mappings
is done as part of VM context destruction; no reference counts are
involved, as is the case for all the other references in the loop.

To break the reference loop during cleanup, free the outstanding
VM mappings before destroying the PVR Context associated with the
VM context.

Signed-off-by: Brendan King <brendan.king@imgtec.com>
Signed-off-by: Matt Coster <matt.coster@imgtec.com>
Reviewed-by: Frank Binns <frank.binns@imgtec.com>
Cc: stable@vger.kernel.org
Link: https://patchwork.freedesktop.org/patch/msgid/8a25924f-1bb7-4d9a-a346-58e871dfb1d1@imgtec.com

authored by

Brendan King and committed by
Matt Coster
b04ce1e7 b0ef514b

+56 -4
+19
drivers/gpu/drm/imagination/pvr_context.c
··· 450 450 */ 451 451 void pvr_destroy_contexts_for_file(struct pvr_file *pvr_file) 452 452 { 453 + struct pvr_device *pvr_dev = pvr_file->pvr_dev; 453 454 struct pvr_context *ctx; 454 455 unsigned long handle; 455 456 456 457 xa_for_each(&pvr_file->ctx_handles, handle, ctx) 457 458 pvr_context_destroy(pvr_file, handle); 459 + 460 + spin_lock(&pvr_dev->ctx_list_lock); 461 + ctx = list_first_entry(&pvr_file->contexts, struct pvr_context, file_link); 462 + 463 + while (!list_entry_is_head(ctx, &pvr_file->contexts, file_link)) { 464 + list_del_init(&ctx->file_link); 465 + 466 + if (pvr_context_get_if_referenced(ctx)) { 467 + spin_unlock(&pvr_dev->ctx_list_lock); 468 + 469 + pvr_vm_unmap_all(ctx->vm_ctx); 470 + 471 + pvr_context_put(ctx); 472 + spin_lock(&pvr_dev->ctx_list_lock); 473 + } 474 + ctx = list_first_entry(&pvr_file->contexts, struct pvr_context, file_link); 475 + } 476 + spin_unlock(&pvr_dev->ctx_list_lock); 458 477 } 459 478 460 479 /**
+18
drivers/gpu/drm/imagination/pvr_context.h
··· 127 127 } 128 128 129 129 /** 130 + * pvr_context_get_if_referenced() - Take an additional reference on a still 131 + * referenced context. 132 + * @ctx: Context pointer. 133 + * 134 + * Call pvr_context_put() to release. 135 + * 136 + * Returns: 137 + * * True on success, or 138 + * * false if no context pointer passed, or the context wasn't still 139 + * * referenced. 140 + */ 141 + static __always_inline bool 142 + pvr_context_get_if_referenced(struct pvr_context *ctx) 143 + { 144 + return ctx != NULL && kref_get_unless_zero(&ctx->ref_count) != 0; 145 + } 146 + 147 + /** 130 148 * pvr_context_lookup() - Lookup context pointer from handle and file. 131 149 * @pvr_file: Pointer to pvr_file structure. 132 150 * @handle: Context handle.
+18 -4
drivers/gpu/drm/imagination/pvr_vm.c
··· 14 14 #include <drm/drm_gem.h> 15 15 #include <drm/drm_gpuvm.h> 16 16 17 + #include <linux/bug.h> 17 18 #include <linux/container_of.h> 18 19 #include <linux/err.h> 19 20 #include <linux/errno.h> ··· 598 597 } 599 598 600 599 /** 601 - * pvr_vm_context_release() - Teardown a VM context. 602 - * @ref_count: Pointer to reference counter of the VM context. 600 + * pvr_vm_unmap_all() - Unmap all mappings associated with a VM context. 601 + * @vm_ctx: Target VM context. 603 602 * 604 603 * This function ensures that no mappings are left dangling by unmapping them 605 604 * all in order of ascending device-virtual address. 605 + */ 606 + void 607 + pvr_vm_unmap_all(struct pvr_vm_context *vm_ctx) 608 + { 609 + WARN_ON(pvr_vm_unmap(vm_ctx, vm_ctx->gpuvm_mgr.mm_start, 610 + vm_ctx->gpuvm_mgr.mm_range)); 611 + } 612 + 613 + /** 614 + * pvr_vm_context_release() - Teardown a VM context. 615 + * @ref_count: Pointer to reference counter of the VM context. 616 + * 617 + * This function also ensures that no mappings are left dangling by calling 618 + * pvr_vm_unmap_all. 606 619 */ 607 620 static void 608 621 pvr_vm_context_release(struct kref *ref_count) ··· 627 612 if (vm_ctx->fw_mem_ctx_obj) 628 613 pvr_fw_object_destroy(vm_ctx->fw_mem_ctx_obj); 629 614 630 - WARN_ON(pvr_vm_unmap(vm_ctx, vm_ctx->gpuvm_mgr.mm_start, 631 - vm_ctx->gpuvm_mgr.mm_range)); 615 + pvr_vm_unmap_all(vm_ctx); 632 616 633 617 pvr_mmu_context_destroy(vm_ctx->mmu_ctx); 634 618 drm_gem_private_object_fini(&vm_ctx->dummy_gem);
+1
drivers/gpu/drm/imagination/pvr_vm.h
··· 39 39 struct pvr_gem_object *pvr_obj, u64 pvr_obj_offset, 40 40 u64 device_addr, u64 size); 41 41 int pvr_vm_unmap(struct pvr_vm_context *vm_ctx, u64 device_addr, u64 size); 42 + void pvr_vm_unmap_all(struct pvr_vm_context *vm_ctx); 42 43 43 44 dma_addr_t pvr_vm_get_page_table_root_addr(struct pvr_vm_context *vm_ctx); 44 45 struct dma_resv *pvr_vm_get_dma_resv(struct pvr_vm_context *vm_ctx);