dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
From: Daniel Vetter <daniel.vetter-/w4YWyX8dFk@public.gmane.org>
To: DRI Development
	<dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org>
Cc: Nouveau Dev
	<nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org>,
	Intel Graphics Development
	<intel-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org>,
	Radeon Dev
	<xorg-driver-ati-go0+a7rfsptAfugRpC6u6w@public.gmane.org>,
	Daniel Vetter <daniel.vetter-/w4YWyX8dFk@public.gmane.org>
Subject: [PATCH 21/37] drm: reference framebuffers which are on the idr
Date: Wed, 12 Dec 2012 14:07:01 +0100	[thread overview]
Message-ID: <1355317637-16742-22-git-send-email-daniel.vetter@ffwll.ch> (raw)
In-Reply-To: <1355317637-16742-1-git-send-email-daniel.vetter-/w4YWyX8dFk@public.gmane.org>

Since otherwise looking and reference-counting around
drm_framebuffer_lookup will be an unmanageable mess. With this change,
an object can either be found in the idr and will stay around once we
incremented the reference counter. Or it will be gone for good and
can't be looked up using its id any more.

Atomicity is guaranteed by the dev->mode_config.fb_lock. The
newly-introduce fpriv->fbs_lock looks a bit redundant, but the next
patch will shuffle the locking order between these two locks and all
the modeset locks taken in modeset_lock_all, so we'll need it.

Also, since userspace could do really funky stuff and race e.g. a
getresources with an rmfb, we need to make sure that the kernel
doesn't fall over trying to look-up an inexistent fb, or causing
confusion by having two fbs around with the same id. Simply reset the
framebuffer id to 0, which marks it as reaped. Any lookups of that id
will fail, so the object is really gone for good from userspace's pov.

Note that we still need to protect the "remove framebuffer from all
use-cases" and the final unreference with the modeset-lock, since most
framebuffer use-sites don't implement proper reference counting yet.
We can only lift this once _all_ users are converted.

With this change, two references are held on alife, but unused
framebuffers:
- The reference for the idr lookup, created in this patch.
- For user-created framebuffers the fpriv->fbs reference, for
  driver-private fbs the driver is supposed to hold it's own last
  reference.

Note that the dev->mode_config.fb_list itself does _not_ hold a
reference onto the framebuffers (this list is essentially only used
for debugfs files). Hence if there's anything left there when the
driver has cleaned up all it's modeset resources, this is a ref-leak.
WARN about it.

Now we only need to fix up all other places to properly reference
count framebuffers.

Signed-off-by: Daniel Vetter <daniel.vetter-/w4YWyX8dFk@public.gmane.org>
---
 drivers/gpu/drm/drm_crtc.c |  118 ++++++++++++++++++++++++++++++--------------
 1 file changed, 80 insertions(+), 38 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index e2d70f6..20ccdc4 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -356,6 +356,9 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
 	if (ret)
 		return ret;
 
+	/* Grab the idr reference. */
+	drm_framebuffer_reference(fb);
+
 	dev->mode_config.num_fb++;
 	list_add(&fb->head, &dev->mode_config.fb_list);
 	mutex_unlock(&dev->mode_config.fb_lock);
@@ -371,6 +374,23 @@ static void drm_framebuffer_free(struct kref *kref)
 	fb->funcs->destroy(fb);
 }
 
+static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev,
+							uint32_t id)
+{
+	struct drm_mode_object *obj = NULL;
+	struct drm_framebuffer *fb;
+
+	mutex_lock(&dev->mode_config.idr_mutex);
+	obj = idr_find(&dev->mode_config.crtc_idr, id);
+	if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id))
+		fb = NULL;
+	else
+		fb = obj_to_fb(obj);
+	mutex_unlock(&dev->mode_config.idr_mutex);
+
+	return fb;
+}
+
 /**
  * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
  * @dev: drm device
@@ -383,22 +403,12 @@ static void drm_framebuffer_free(struct kref *kref)
 struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
 					       uint32_t id)
 {
-	struct drm_mode_object *obj = NULL;
 	struct drm_framebuffer *fb;
 
 	mutex_lock(&dev->mode_config.fb_lock);
-
-	mutex_lock(&dev->mode_config.idr_mutex);
-	obj = idr_find(&dev->mode_config.crtc_idr, id);
-	if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id))
-		fb = NULL;
-	else
-		fb = obj_to_fb(obj);
-	mutex_unlock(&dev->mode_config.idr_mutex);
-
+	fb = __drm_framebuffer_lookup(dev, id);
 	if (fb)
 		kref_get(&fb->refcount);
-
 	mutex_unlock(&dev->mode_config.fb_lock);
 
 	return fb;
@@ -429,6 +439,24 @@ void drm_framebuffer_reference(struct drm_framebuffer *fb)
 }
 EXPORT_SYMBOL(drm_framebuffer_reference);
 
+static void drm_framebuffer_free_bug(struct kref *kref)
+{
+	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;
+
+	kref_put(&fb->refcount, drm_framebuffer_free_bug);
+}
+
 /**
  * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
  * @fb: fb to unregister
@@ -440,6 +468,12 @@ EXPORT_SYMBOL(drm_framebuffer_reference);
  */
 void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
 {
+	struct drm_device *dev = fb->dev;
+
+	mutex_lock(&dev->mode_config.fb_lock);
+	/* Mark fb as reaped and drop idr ref. */
+	__drm_framebuffer_unregister(dev, fb);
+	mutex_unlock(&dev->mode_config.fb_lock);
 }
 EXPORT_SYMBOL(drm_framebuffer_unregister_private);
 
@@ -463,14 +497,6 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
 {
 	struct drm_device *dev = fb->dev;
 
-	/*
-	 * This could be moved to drm_framebuffer_remove(), but for
-	 * debugging is nice to keep around the list of fb's that are
-	 * no longer associated w/ a drm_file but are not unreferenced
-	 * yet.  (i915 and omapdrm have debugfs files which will show
-	 * this.)
-	 */
-	drm_mode_object_put(dev, &fb->base);
 	mutex_lock(&dev->mode_config.fb_lock);
 	list_del(&fb->head);
 	dev->mode_config.num_fb--;
@@ -1180,9 +1206,15 @@ void drm_mode_config_cleanup(struct drm_device *dev)
 		drm_property_destroy(dev, property);
 	}
 
-	/* Single-threaded teardown context, so it's not requied to grab the
+	/*
+	 * Single-threaded teardown context, so it's not requied to grab the
 	 * fb_lock to protect against concurrent fb_list access. Contrary, it
-	 * would actually deadlock with the drm_framebuffer_cleanup function. */
+	 * would actually deadlock with the drm_framebuffer_cleanup function.
+	 *
+	 * Also, if there are any framebuffers left, that's a driver leak now,
+	 * so politely WARN about this.
+	 */
+	WARN_ON(!list_empty(&dev->mode_config.fb_list));
 	list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
 		drm_framebuffer_remove(fb);
 	}
@@ -2448,39 +2480,41 @@ int drm_mode_rmfb(struct drm_device *dev,
 	struct drm_framebuffer *fb = NULL;
 	struct drm_framebuffer *fbl = NULL;
 	uint32_t *id = data;
-	int ret = 0;
 	int found = 0;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	drm_modeset_lock_all(dev);
-	fb = drm_framebuffer_lookup(dev, *id);
-	if (!fb) {
-		ret = -EINVAL;
-		goto out;
-	}
-	/* fb is protect by the mode_config lock, so drop the ref immediately */
-	drm_framebuffer_unreference(fb);
-
 	mutex_lock(&file_priv->fbs_lock);
+	mutex_lock(&dev->mode_config.fb_lock);
+	fb = __drm_framebuffer_lookup(dev, *id);
+	if (!fb)
+		goto fail_lookup;
+
 	list_for_each_entry(fbl, &file_priv->fbs, filp_head)
 		if (fb == fbl)
 			found = 1;
-	if (!found) {
-		ret = -EINVAL;
-		mutex_unlock(&file_priv->fbs_lock);
-		goto out;
-	}
+	if (!found)
+		goto fail_lookup;
+
+	/* Mark fb as reaped, we still have a ref from fpriv->fbs. */
+	__drm_framebuffer_unregister(dev, fb);
 
 	list_del_init(&fb->filp_head);
+	mutex_unlock(&dev->mode_config.fb_lock);
 	mutex_unlock(&file_priv->fbs_lock);
 
+	drm_modeset_lock_all(dev);
 	drm_framebuffer_remove(fb);
-out:
 	drm_modeset_unlock_all(dev);
 
-	return ret;
+	return 0;
+
+fail_lookup:
+	mutex_unlock(&dev->mode_config.fb_lock);
+	mutex_unlock(&file_priv->fbs_lock);
+
+	return -EINVAL;
 }
 
 /**
@@ -2620,7 +2654,15 @@ void drm_fb_release(struct drm_file *priv)
 	drm_modeset_lock_all(dev);
 	mutex_lock(&priv->fbs_lock);
 	list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
+
+		mutex_lock(&dev->mode_config.fb_lock);
+		/* Mark fb as reaped, we still have a ref from fpriv->fbs. */
+		__drm_framebuffer_unregister(dev, fb);
+		mutex_unlock(&dev->mode_config.fb_lock);
+
 		list_del_init(&fb->filp_head);
+
+		/* This will also drop the fpriv->fbs reference. */
 		drm_framebuffer_remove(fb);
 	}
 	mutex_unlock(&priv->fbs_lock);
-- 
1.7.10.4

  parent reply	other threads:[~2012-12-12 13:07 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-12-12 13:06 [PATCH 00/37] [RFC] revamped modeset locking Daniel Vetter
2012-12-12 13:06 ` [PATCH 01/37] drm: review locking rules in drm_crtc.c Daniel Vetter
2012-12-12 13:06 ` [PATCH 05/37] drm/i915: use drm_modeset_lock_all Daniel Vetter
2012-12-12 13:06 ` [PATCH 08/37] drm/shmobile: " Daniel Vetter
2012-12-12 13:06 ` [PATCH 10/37] drm: add per-crtc locks Daniel Vetter
2012-12-13 11:38   ` [Intel-gfx] " Ville Syrjälä
2012-12-13 11:54     ` Daniel Vetter
2012-12-13 14:25       ` Ville Syrjälä
2012-12-12 13:06 ` [PATCH 11/37] drm/radeon: add W|RREG32_IDX for MM_INDEX|DATA based mmio accesss Daniel Vetter
2012-12-12 13:07 ` [PATCH 25/37] drm: don't take modeset locks in getfb ioctl Daniel Vetter
2012-12-12 13:07 ` [PATCH 26/37] drm: fb refcounting for dirtyfb_ioctl Daniel Vetter
2012-12-12 13:07 ` [PATCH 31/37] drm/vmwgfx: add proper framebuffer refcounting Daniel Vetter
2012-12-12 13:07 ` [PATCH 33/37] drm/nouveau: try to protect nbo->pin_refcount Daniel Vetter
     [not found] ` <1355317637-16742-1-git-send-email-daniel.vetter-/w4YWyX8dFk@public.gmane.org>
2012-12-12 13:06   ` [PATCH 02/37] drm/doc: integrate drm_crtc.c kerneldoc Daniel Vetter
2012-12-12 13:06   ` [PATCH 03/37] drm: add drm_modeset_lock|unlock_all Daniel Vetter
2012-12-12 13:06   ` [PATCH 04/37] drm/i915: rework locking for intel_dpio|sbi_read|write Daniel Vetter
2012-12-12 20:54     ` [Intel-gfx] " Jesse Barnes
2012-12-12 22:00       ` Daniel Vetter
2012-12-12 22:05         ` Jesse Barnes
2012-12-12 13:06   ` [PATCH 06/37] drm/gma500: use drm_modeset_lock_all Daniel Vetter
2012-12-12 13:06   ` [PATCH 07/37] drm/ast: " Daniel Vetter
2012-12-12 13:06   ` [PATCH 09/37] drm/vmgfx: " Daniel Vetter
2012-12-12 13:06   ` [PATCH 12/37] drm/radeon: make indirect register access concurrency-safe Daniel Vetter
2012-12-12 13:06   ` [PATCH 13/37] drm/nouveau: protect evo_wait/evo_kick sections with a channel mutex Daniel Vetter
2012-12-12 13:06   ` [PATCH 14/37] drm: only take the crtc lock for ->cursor_set Daniel Vetter
2012-12-12 13:06   ` [PATCH 15/37] drm: only take the crtc lock for ->cursor_move Daniel Vetter
2012-12-13 11:03     ` [PATCH] " Daniel Vetter
2012-12-12 13:06   ` [PATCH 16/37] drm/<drivers>: reorder framebuffer init sequence Daniel Vetter
2012-12-13 11:05     ` [PATCH 1/2] " Daniel Vetter
     [not found]       ` <1355396719-25286-1-git-send-email-daniel.vetter-/w4YWyX8dFk@public.gmane.org>
2012-12-13 11:05         ` [PATCH 2/2] drm/exynos: " Daniel Vetter
2012-12-13 12:26           ` Inki Dae
2012-12-13 12:43             ` Daniel Vetter
2012-12-13 15:16               ` Inki Dae
2012-12-13 16:38                 ` Daniel Vetter
2012-12-14  4:57                   ` Inki Dae
2012-12-14  8:40                     ` Daniel Vetter
2012-12-12 13:06   ` [PATCH 17/37] drm: revamp locking around fb creation/destruction Daniel Vetter
2012-12-12 13:06   ` [PATCH 18/37] drm: create drm_framebuffer_lookup Daniel Vetter
2012-12-12 13:06   ` [PATCH 19/37] drm/gma500: move fbcon restore to lastclose Daniel Vetter
2012-12-12 13:07   ` [PATCH 20/37] drm: revamp framebuffer cleanup interfaces Daniel Vetter
2012-12-12 13:07   ` Daniel Vetter [this message]
2012-12-12 13:07   ` [PATCH 22/37] drm: nest modeset locks within fpriv->fbs_lock Daniel Vetter
2012-12-12 13:07   ` [PATCH 23/37] drm/i915: fixup overlay stolen memory leak Daniel Vetter
2012-12-12 13:07   ` [PATCH 24/37] drm: push modeset_lock_all into ->fb_create driver callbacks Daniel Vetter
2012-12-12 13:07   ` [PATCH 27/37] drm: refcounting for sprite framebuffers Daniel Vetter
2012-12-12 13:07   ` [PATCH 28/37] drm: encapsulate crtc->set_config calls Daniel Vetter
2012-12-12 13:07   ` [PATCH 29/37] drm: refcounting for crtc framebuffers Daniel Vetter
2012-12-12 13:07   ` [PATCH 30/37] drm/i915: dump refcount into framebuffer debugfs file Daniel Vetter
2012-12-12 13:07   ` [PATCH 32/37] drm: optimize drm_framebuffer_remove Daniel Vetter
2012-12-12 13:07   ` [PATCH 34/37] drm/ttm: fix fence locking in ttm_buffer_object_transfer Daniel Vetter
2012-12-12 14:48     ` Jerome Glisse
     [not found]       ` <CAH3drwbL34+omj2S3ArOPgoYRQ3uzPEiRPFLn7YkP3cOMnPiZg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-12-12 15:42         ` Daniel Vetter
2012-12-13 11:06     ` [PATCH] allow shmob+imx drm drivers to be compiled Daniel Vetter
2012-12-13 11:18     ` Daniel Vetter
2012-12-13 11:26     ` [PATCH] drm/ttm: fix fence locking in ttm_buffer_object_transfer Daniel Vetter
2012-12-12 13:07   ` [PATCH 35/37] drm/radeon: fix fence locking in the pageflip callback Daniel Vetter
2012-12-12 13:07   ` [PATCH 36/37] drm: only grab the crtc lock for pageflips Daniel Vetter
2012-12-12 13:07   ` [PATCH 37/37] drm: don't hold crtc mutexes for connector ->detect callbacks Daniel Vetter
2012-12-12 14:18 ` [PATCH 00/37] [RFC] revamped modeset locking Daniel Vetter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1355317637-16742-22-git-send-email-daniel.vetter@ffwll.ch \
    --to=daniel.vetter-/w4ywyx8dfk@public.gmane.org \
    --cc=dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org \
    --cc=intel-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org \
    --cc=nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org \
    --cc=xorg-driver-ati-go0+a7rfsptAfugRpC6u6w@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).