virgl: fix reference counting of prime handles
authorRob Herring <robh@kernel.org>
Fri, 29 Jan 2016 22:36:29 +0000 (16:36 -0600)
committerDave Airlie <airlied@redhat.com>
Mon, 1 Feb 2016 23:58:29 +0000 (09:58 +1000)
The virgl reference counting of buffers is broken for prime fd buffers.
Each prime fd passed into virgl_drm_winsys_resource_create_handle creates
a new resource. The solution requires creating a separate hash table to
track flink names separately from prime handles.

Signed-off-by: Rob Herring <robh@kernel.org>
Signed-off-by: Dave Airlie <airlied@redhat.com>
src/gallium/winsys/virgl/drm/virgl_drm_winsys.c
src/gallium/winsys/virgl/drm/virgl_drm_winsys.h

index 48a79faa4bb13c82ea1920c432f2d8721942eab2..a49a89ebc999bf8c47d9ec6cf7f3d7d605de7e45 100644 (file)
@@ -53,10 +53,17 @@ static void virgl_hw_res_destroy(struct virgl_drm_winsys *qdws,
 {
       struct drm_gem_close args;
 
-      if (res->name) {
+      if (res->flinked) {
+         pipe_mutex_lock(qdws->bo_handles_mutex);
+         util_hash_table_remove(qdws->bo_names,
+                                (void *)(uintptr_t)res->flink);
+         pipe_mutex_unlock(qdws->bo_handles_mutex);
+      }
+
+      if (res->bo_handle) {
          pipe_mutex_lock(qdws->bo_handles_mutex);
          util_hash_table_remove(qdws->bo_handles,
-                                (void *)(uintptr_t)res->name);
+                                (void *)(uintptr_t)res->bo_handle);
          pipe_mutex_unlock(qdws->bo_handles_mutex);
       }
 
@@ -112,6 +119,7 @@ virgl_drm_winsys_destroy(struct virgl_winsys *qws)
    virgl_cache_flush(qdws);
 
    util_hash_table_destroy(qdws->bo_handles);
+   util_hash_table_destroy(qdws->bo_names);
    pipe_mutex_destroy(qdws->bo_handles_mutex);
    pipe_mutex_destroy(qdws->mutex);
 
@@ -370,11 +378,12 @@ virgl_drm_winsys_resource_create_handle(struct virgl_winsys *qws,
    struct drm_gem_open open_arg = {};
    struct drm_virtgpu_resource_info info_arg = {};
    struct virgl_hw_res *res;
+   uint32_t handle = whandle->handle;
 
    pipe_mutex_lock(qdws->bo_handles_mutex);
 
    if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) {
-      res = util_hash_table_get(qdws->bo_handles, (void*)(uintptr_t)whandle->handle);
+      res = util_hash_table_get(qdws->bo_names, (void*)(uintptr_t)handle);
       if (res) {
          struct virgl_hw_res *r = NULL;
          virgl_drm_resource_reference(qdws, &r, res);
@@ -382,21 +391,31 @@ virgl_drm_winsys_resource_create_handle(struct virgl_winsys *qws,
       }
    }
 
-   res = CALLOC_STRUCT(virgl_hw_res);
-   if (!res)
-      goto done;
-
    if (whandle->type == DRM_API_HANDLE_TYPE_FD) {
       int r;
-      uint32_t handle;
       r = drmPrimeFDToHandle(qdws->fd, whandle->handle, &handle);
       if (r) {
-         FREE(res);
          res = NULL;
          goto done;
       }
+   }
+
+   res = util_hash_table_get(qdws->bo_handles, (void*)(uintptr_t)handle);
+   fprintf(stderr, "resource %p for handle %d, pfd=%d\n", res, handle, whandle->handle);
+   if (res) {
+      struct virgl_hw_res *r = NULL;
+      virgl_drm_resource_reference(qdws, &r, res);
+      goto done;
+   }
+
+   res = CALLOC_STRUCT(virgl_hw_res);
+   if (!res)
+      goto done;
+
+   if (whandle->type == DRM_API_HANDLE_TYPE_FD) {
       res->bo_handle = handle;
    } else {
+      fprintf(stderr, "gem open handle %d\n", handle);
       memset(&open_arg, 0, sizeof(open_arg));
       open_arg.name = whandle->handle;
       if (drmIoctl(qdws->fd, DRM_IOCTL_GEM_OPEN, &open_arg)) {
@@ -406,7 +425,7 @@ virgl_drm_winsys_resource_create_handle(struct virgl_winsys *qws,
       }
       res->bo_handle = open_arg.handle;
    }
-   res->name = whandle->handle;
+   res->name = handle;
 
    memset(&info_arg, 0, sizeof(info_arg));
    info_arg.bo_handle = res->bo_handle;
@@ -425,7 +444,7 @@ virgl_drm_winsys_resource_create_handle(struct virgl_winsys *qws,
    pipe_reference_init(&res->reference, 1);
    res->num_cs_references = 0;
 
-   util_hash_table_set(qdws->bo_handles, (void *)(uintptr_t)whandle->handle, res);
+   util_hash_table_set(qdws->bo_handles, (void *)(uintptr_t)handle, res);
 
 done:
    pipe_mutex_unlock(qdws->bo_handles_mutex);
@@ -455,7 +474,7 @@ static boolean virgl_drm_winsys_resource_get_handle(struct virgl_winsys *qws,
          res->flink = flink.name;
 
          pipe_mutex_lock(qdws->bo_handles_mutex);
-         util_hash_table_set(qdws->bo_handles, (void *)(uintptr_t)res->flink, res);
+         util_hash_table_set(qdws->bo_names, (void *)(uintptr_t)res->flink, res);
          pipe_mutex_unlock(qdws->bo_handles_mutex);
       }
       whandle->handle = res->flink;
@@ -751,6 +770,7 @@ virgl_drm_winsys_create(int drmFD)
    pipe_mutex_init(qdws->mutex);
    pipe_mutex_init(qdws->bo_handles_mutex);
    qdws->bo_handles = util_hash_table_create(handle_hash, handle_compare);
+   qdws->bo_names = util_hash_table_create(handle_hash, handle_compare);
    qdws->base.destroy = virgl_drm_winsys_destroy;
 
    qdws->base.transfer_put = virgl_bo_transfer_put;
index da85ff87d2a5aa4c6e2446d6f95618a9dfdfc9cf..ffd7658ca81faf6e2a6569c92fca4827faa62aa2 100644 (file)
@@ -62,6 +62,7 @@ struct virgl_drm_winsys
    pipe_mutex mutex;
 
    struct util_hash_table *bo_handles;
+   struct util_hash_table *bo_names;
    pipe_mutex bo_handles_mutex;
 };