From 160137ccaeb925ada3936e4e0099f8d7662bacea Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 25 Jan 2023 11:57:28 -0800 Subject: [PATCH] freedreno/drm: Detect zombie BOs When importing from a GEM name or dmabuf fd, we can race with the final unref of the same BO, in which case we can get a hit in the handle table for an fd_bo that another thread is about to free(). Detect and handle this case. Signed-off-by: Rob Clark Part-of: --- src/freedreno/drm/freedreno_bo.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/freedreno/drm/freedreno_bo.c b/src/freedreno/drm/freedreno_bo.c index 0666195868b..d04d8ddb578 100644 --- a/src/freedreno/drm/freedreno_bo.c +++ b/src/freedreno/drm/freedreno_bo.c @@ -46,10 +46,28 @@ static struct fd_bo * lookup_bo(struct hash_table *tbl, uint32_t key) { struct fd_bo *bo = NULL; - struct hash_entry *entry = _mesa_hash_table_search(tbl, &key); + struct hash_entry *entry; + + simple_mtx_assert_locked(&table_lock); + + entry = _mesa_hash_table_search(tbl, &key); if (entry) { + bo = entry->data; + + /* We could be racing with final unref in another thread, and won + * the table_lock preventing the other thread from being able to + * remove an object it is about to free. Fortunately since table + * lookup and removal are protected by the same lock (and table + * removal happens before obj free) we can easily detect this by + * checking for refcnt==0. + */ + if (bo->refcnt == 0) { + bo->handle = 0; + return NULL; + } + /* found, incr refcnt and return: */ - bo = fd_bo_ref(entry->data); + fd_bo_ref(bo); if (!list_is_empty(&bo->node)) { mesa_logw("bo was in cache, size=%u, alloc_flags=0x%x\n",