drm/gem: Fix GEM handle release errors
authorjsg <jsg@openbsd.org>
Fri, 16 Sep 2022 02:16:44 +0000 (02:16 +0000)
committerjsg <jsg@openbsd.org>
Fri, 16 Sep 2022 02:16:44 +0000 (02:16 +0000)
From Jeffy Chen
1f574fbe9c2b831a8c3156260842a7abd280d59f in linux 5.15.y/5.15.68
ea2aa97ca37a9044ade001aef71dbc06318e8d44 in mainline linux

sys/dev/pci/drm/drm_gem.c
sys/dev/pci/drm/drm_internal.h
sys/dev/pci/drm/drm_prime.c

index b6b4999..9937874 100644 (file)
@@ -351,21 +351,6 @@ void drm_gem_private_object_init(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_gem_private_object_init);
 
-static void
-drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
-{
-       /*
-        * Note: obj->dma_buf can't disappear as long as we still hold a
-        * handle reference in obj->handle_count.
-        */
-       mutex_lock(&filp->prime.lock);
-       if (obj->dma_buf) {
-               drm_prime_remove_buf_handle_locked(&filp->prime,
-                                                  obj->dma_buf);
-       }
-       mutex_unlock(&filp->prime.lock);
-}
-
 /**
  * drm_gem_object_handle_free - release resources bound to userspace handles
  * @obj: GEM object to clean up.
@@ -436,7 +421,7 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
        if (obj->funcs->close)
                obj->funcs->close(obj, file_priv);
 
-       drm_gem_remove_prime_handles(obj, file_priv);
+       drm_prime_remove_buf_handle(&file_priv->prime, id);
        drm_vma_node_revoke(&obj->vma_node, file_priv);
 
        drm_gem_object_handle_put_unlocked(obj);
index c776ac3..2ea2762 100644 (file)
@@ -74,8 +74,8 @@ int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
 
 void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv);
 void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
-void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
-                                       struct dma_buf *dma_buf);
+void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv,
+                                uint32_t handle);
 
 /* drm_drv.c */
 struct drm_minor *drm_minor_acquire(unsigned int minor_id);
index 5c9e8b8..0cb3d67 100644 (file)
@@ -187,29 +187,33 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri
        return -ENOENT;
 }
 
-void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
-                                       struct dma_buf *dma_buf)
+void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv,
+                                uint32_t handle)
 {
        struct rb_node *rb;
 
-       rb = prime_fpriv->dmabufs.rb_node;
+       mutex_lock(&prime_fpriv->lock);
+
+       rb = prime_fpriv->handles.rb_node;
        while (rb) {
                struct drm_prime_member *member;
 
-               member = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
-               if (member->dma_buf == dma_buf) {
+               member = rb_entry(rb, struct drm_prime_member, handle_rb);
+               if (member->handle == handle) {
                        rb_erase(&member->handle_rb, &prime_fpriv->handles);
                        rb_erase(&member->dmabuf_rb, &prime_fpriv->dmabufs);
 
-                       dma_buf_put(dma_buf);
+                       dma_buf_put(member->dma_buf);
                        kfree(member);
-                       return;
-               } else if (member->dma_buf < dma_buf) {
+                       break;
+               } else if (member->handle < handle) {
                        rb = rb->rb_right;
                } else {
                        rb = rb->rb_left;
                }
        }
+
+       mutex_unlock(&prime_fpriv->lock);
 }
 
 void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)