Message ID | 20220819072834.17888-1-jeffy.chen@rock-chips.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v3] drm/gem: Fix GEM handle release errors | expand |
Am 19.08.22 um 09:28 schrieb Jeffy Chen: > Currently we are assuming a one to one mapping between dmabuf and > GEM handle when releasing GEM handles. > > But that is not always true, since we would create extra handles for the > GEM obj in cases like gem_open() and getfb{,2}(). > > A similar issue was reported at: > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.kernel.org%2Fall%2F20211105083308.392156-1-jay.xu%40rock-chips.com%2F&data=05%7C01%7Cchristian.koenig%40amd.com%7Cd1716ddbdbea410a724408da81b52ba2%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637964912375829248%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=uNdN7MgujJMgBMISdZowKDh1PFZ2sqsueCvn%2BX1hYuc%3D&reserved=0 > > Another problem is that the imported dmabuf might not always have > gem_obj->dma_buf set, which would cause leaks in > drm_gem_remove_prime_handles(). > > Let's fix these for now by using handle to find the exact map to remove. > > Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> > Reviewed-by: Christian König <christian.koenig@amd.com> I've just pushed this one to drm-misc-fixes. Thanks, Christian. > > --- > > Changes in v3: > Rewrite commit message a bit. > > Changes in v2: > Fix a typo of rbtree. > > drivers/gpu/drm/drm_gem.c | 17 +---------------- > drivers/gpu/drm/drm_internal.h | 4 ++-- > drivers/gpu/drm/drm_prime.c | 20 ++++++++++++-------- > 3 files changed, 15 insertions(+), 26 deletions(-) > > diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c > index eb0c2d041f13..ed39da383570 100644 > --- a/drivers/gpu/drm/drm_gem.c > +++ b/drivers/gpu/drm/drm_gem.c > @@ -168,21 +168,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. > @@ -253,7 +238,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); > diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h > index 1fbbc19f1ac0..7bb98e6a446d 100644 > --- a/drivers/gpu/drm/drm_internal.h > +++ b/drivers/gpu/drm/drm_internal.h > @@ -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); > diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c > index e3f09f18110c..bd5366b16381 100644 > --- a/drivers/gpu/drm/drm_prime.c > +++ b/drivers/gpu/drm/drm_prime.c > @@ -190,29 +190,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)
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index eb0c2d041f13..ed39da383570 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -168,21 +168,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. @@ -253,7 +238,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); diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 1fbbc19f1ac0..7bb98e6a446d 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -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); diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index e3f09f18110c..bd5366b16381 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -190,29 +190,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)