[PATCH] drm: Don't grab an fb reference for the idr
Rob Clark
robdclark at gmail.com
Wed Aug 6 04:11:28 PDT 2014
On Wed, Aug 6, 2014 at 3:10 AM, Daniel Vetter <daniel.vetter at ffwll.ch> wrote:
> The current refcounting scheme is that the fb lookup idr also holds a
> reference. This works out nicely bacause thus far we've always
> explicitly cleaned up idr entries for framebuffers:
> - Userspace fbs get removed in the rmfb ioctl or when the drm file
> gets closed.
> - Kernel fbs (for fbdev emulation) get cleaned up by the driver code
> at module unload time.
>
> But now i915 also reconstructs the bios fbs for a smooth transition.
> And that fb is purely transitional and should get removed immmediately
> once all crtcs stop using it. Of course if the i915 fbdev code decides
> to reuse it as the main fbdev fb then it shouldn't be cleaned up, but
> in that case the fbdev code will grab it's own reference.
>
> The problem is now that we also want to register that takeover fb in
> the idr, so that userspace can do a smooth transition (animated maybe
> even!) itself. But currently we have no one who will clean up the idr
> reference once that fb isn't useful any more, and so essentially leak
> it.
ewww.. couldn't you do some scheme on lastclose to check if no more
crtc's are scanning out that fb, and if not then remove the idr?
BR,
-R
> Fix this by no longer holding a full fb reference for the idr, but
> instead just have a weak reference using kref_get_unless_zero. But
> that requires us to synchronize and clean up with the idr and fb_lock
> in drm_framebuffer_free, so add that. It's a bit ugly that we have to
> unconditionally grab the fb_lock, but without that someone might creep
> through a race.
>
> This leak was caught by the fb leak check in drm_mode_config_cleanup.
> Originally the leak was introduced in
>
> commit 46f297fb83d4f9a6f6891964beb184664341a28b
> Author: Jesse Barnes <jbarnes at virtuousgeek.org>
> Date: Fri Mar 7 08:57:48 2014 -0800
>
> drm/i915: add plane_config fetching infrastructure v2
>
> Cc: Jesse Barnes <jbarnes at virtuousgeek.org>
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=77511
> Signed-off-by: Daniel Vetter <daniel.vetter at ffwll.ch>
> ---
> drivers/gpu/drm/drm_crtc.c | 46 ++++++++++++++++++++++++++++------------------
> 1 file changed, 28 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index fa2be249999c..33ff631c8d23 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -515,9 +515,6 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
> if (ret)
> goto out;
>
> - /* Grab the idr reference. */
> - drm_framebuffer_reference(fb);
> -
> dev->mode_config.num_fb++;
> list_add(&fb->head, &dev->mode_config.fb_list);
> out:
> @@ -527,10 +524,34 @@ out:
> }
> EXPORT_SYMBOL(drm_framebuffer_init);
>
> +/* dev->mode_config.fb_lock must be held! */
> +static void __drm_framebuffer_unregister(struct drm_device *dev,
> + struct drm_framebuffer *fb)
> +{
> + mutex_lock(&dev->mode_config.idr_mutex);
> + idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
> + mutex_unlock(&dev->mode_config.idr_mutex);
> +
> + fb->base.id = 0;
> +}
> +
> static void drm_framebuffer_free(struct kref *kref)
> {
> struct drm_framebuffer *fb =
> container_of(kref, struct drm_framebuffer, refcount);
> + struct drm_device *dev = fb->dev;
> +
> + /*
> + * The lookup idr holds a weak reference, which has not necessarily been
> + * removed at this point. Check for that.
> + */
> + mutex_lock(&dev->mode_config.fb_lock);
> + if (fb->base.id) {
> + /* Mark fb as reaped and drop idr ref. */
> + __drm_framebuffer_unregister(dev, fb);
> + }
> + mutex_unlock(&dev->mode_config.fb_lock);
> +
> fb->funcs->destroy(fb);
> }
>
> @@ -567,8 +588,10 @@ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
>
> mutex_lock(&dev->mode_config.fb_lock);
> fb = __drm_framebuffer_lookup(dev, id);
> - if (fb)
> - drm_framebuffer_reference(fb);
> + if (fb) {
> + if (!kref_get_unless_zero(&fb->refcount))
> + fb = NULL;
> + }
> mutex_unlock(&dev->mode_config.fb_lock);
>
> return fb;
> @@ -612,19 +635,6 @@ static void __drm_framebuffer_unreference(struct drm_framebuffer *fb)
> kref_put(&fb->refcount, drm_framebuffer_free_bug);
> }
>
> -/* dev->mode_config.fb_lock must be held! */
> -static void __drm_framebuffer_unregister(struct drm_device *dev,
> - struct drm_framebuffer *fb)
> -{
> - mutex_lock(&dev->mode_config.idr_mutex);
> - idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
> - mutex_unlock(&dev->mode_config.idr_mutex);
> -
> - fb->base.id = 0;
> -
> - __drm_framebuffer_unreference(fb);
> -}
> -
> /**
> * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
> * @fb: fb to unregister
> --
> 1.9.3
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
More information about the dri-devel
mailing list