freedreno/drm: Detect zombie BOs
authorRob Clark <robdclark@chromium.org>
Wed, 25 Jan 2023 19:57:28 +0000 (11:57 -0800)
committerMarge Bot <emma+marge@anholt.net>
Thu, 26 Jan 2023 22:21:47 +0000 (22:21 +0000)
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 <robdclark@chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20918>

src/freedreno/drm/freedreno_bo.c

index 0666195..d04d8dd 100644 (file)
@@ -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",