From 871a933cacb734e4a3643e0f29c0ff67a832fc6b Mon Sep 17 00:00:00 2001 From: Xianzhong Li Date: Fri, 3 Apr 2026 14:17:07 +0800 Subject: [PATCH] panfrost: Fix GEM handle refcount leak in panfrost_bo_import panfrost_bo_import() calls drmPrimeFDToHandle() then pan_kmod_bo_import(), which also calls drmPrimeFDToHandle() internally. This double import causes GEM handle refcount leaks because each drmPrimeFDToHandle() increments the kernel's GEM handle refcount, but only one drmCloseBufferHandle() is called during cleanup by panfrost_kmod_bo_free(or panthor_kmod_bo_free). Fix by removing the redundant drmPrimeFDToHandle() and using pan_kmod_bo_import() directly. On re-import of existing buffers, properly release the extra pan_kmod_bo reference with pan_kmod_bo_put(). This ensures GEM handle refcount, pan_kmod_bo refcount, and panfrost_bo refcount are all properly balanced. Fixes: 5089a758dfb1 ("panfrost: Back panfrost_bo with pan_kmod_bo object") Signed-off-by: Xianzhong Li Reviewed-by: Boris Brezillon Reviewed-by: Eric R. Smith (cherry picked from commit 248b0b47b74abf51fdda1ae10ca573cbab78c89a) Part-of: --- .pick_status.json | 2 +- src/gallium/drivers/panfrost/pan_bo.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/.pick_status.json b/.pick_status.json index 15cd0dfad39..0f42c10b83b 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -3744,7 +3744,7 @@ "description": "panfrost: Fix GEM handle refcount leak in panfrost_bo_import", "nominated": true, "nomination_type": 2, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": "5089a758dfb1760a0dc397b0f491c4a6dc2160af", "notes": null diff --git a/src/gallium/drivers/panfrost/pan_bo.c b/src/gallium/drivers/panfrost/pan_bo.c index ba35fc81150..9e6ffbd09bb 100644 --- a/src/gallium/drivers/panfrost/pan_bo.c +++ b/src/gallium/drivers/panfrost/pan_bo.c @@ -471,18 +471,24 @@ struct panfrost_bo * panfrost_bo_import(struct panfrost_device *dev, int fd) { struct panfrost_bo *bo; - ASSERTED int ret; + struct pan_kmod_bo *kmod_bo; unsigned gem_handle; pthread_mutex_lock(&dev->bo_map_lock); - ret = drmPrimeFDToHandle(dev->kmod.dev->fd, fd, &gem_handle); - assert(!ret); + /* Import via pan_kmod_bo_import - it handles drmPrimeFDToHandle internally */ + kmod_bo = pan_kmod_bo_import(dev->kmod.dev, fd, 0); + if (!kmod_bo) { + pthread_mutex_unlock(&dev->bo_map_lock); + return NULL; + } + /* Look up panfrost_bo by the GEM handle from kmod_bo */ + gem_handle = pan_kmod_bo_handle(kmod_bo); bo = pan_lookup_bo(dev, gem_handle); if (!bo->dev) { bo->dev = dev; - bo->kmod_bo = pan_kmod_bo_import(dev->kmod.dev, fd, 0); + bo->kmod_bo = kmod_bo; /* Take ownership of kmod_bo reference */ struct pan_kmod_vm_op vm_op = { .type = PAN_KMOD_VM_OP_TYPE_MAP, @@ -510,6 +516,12 @@ panfrost_bo_import(struct panfrost_device *dev, int fd) if ((dev->debug & PAN_DBG_DUMP) && panfrost_bo_mmap(bo)) mesa_loge("failed to mmap"); } else { + /* pan_kmod_bo_import already incremented kmod_bo->refcnt, + * but we already have a reference in bo->kmod_bo, + * so release this extra kmod_bo reference. + */ + pan_kmod_bo_put(kmod_bo); + /* bo->refcnt == 0 can happen if the BO * was being released but panfrost_bo_import() acquired the * lock before panfrost_bo_unreference(). In that case, refcnt