aboutsummaryrefslogtreecommitdiffstats
path: root/include/drm
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2013-08-14 18:02:37 -0400
committerDave Airlie <airlied@redhat.com>2013-08-20 22:53:45 -0400
commita8e11d1c435f9d185c9f3b1981b9613a579b9999 (patch)
treefc0b5793a69d06045149a47c01edca0ed8be9905 /include/drm
parent9712def2b3e10081b5f7d3c3bddad3126df4f0ba (diff)
drm/gem: fix up flink name create race
This is the 2nd attempt, I've always been a bit dissatisified with the tricky nature of the first one: http://lists.freedesktop.org/archives/dri-devel/2012-July/025451.html The issue is that the flink ioctl can race with calling gem_close on the last gem handle. In that case we'll end up with a zero handle count, but an flink name (and it's corresponding reference). Which results in a neat space leak. In my first attempt I've solved this by rechecking the handle count. But fundamentally the issue is that ->handle_count isn't your usual refcount - it can be resurrected from 0 among other things. For those special beasts atomic_t often suggest way more ordering that it actually guarantees. To prevent being tricked by those hairy semantics take the easy way out and simply protect the handle with the existing dev->object_name_lock. With that change implemented it's dead easy to fix the flink vs. gem close reace: When we try to create the name we simply have to check whether there's still officially a gem handle around and if not refuse to create the flink name. Since the handle count decrement and flink name destruction is now also protected by that lock the reace is gone and we can't ever leak the flink reference again. Outside of the drm core only the exynos driver looks at the handle count, and tbh I have no idea why (it's just for debug dmesg output luckily). I've considered inlining the drm_gem_object_handle_free, but I plan to add more name-like things (like the exported dma_buf) to this scheme, so it's clearer to leave the handle freeing in its own function. This is exercised by the new gem_flink_race i-g-t testcase, which on my snb leaks gem objects at a rate of roughly 1k objects/s. v2: Fix up the error path handling in handle_create and make it more robust by simply calling object_handle_unreference. v3: Fix up the handle_unreference logic bug - atomic_dec_and_test retursn 1 for 0. Oops. v4: Squash in inlining of drm_gem_object_handle_reference as suggested by Dave Airlie and add a note that we now have a testcase. Cc: Dave Airlie <airlied@gmail.com> Cc: Inki Dae <inki.dae@samsung.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'include/drm')
-rw-r--r--include/drm/drmP.h19
1 files changed, 10 insertions, 9 deletions
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 1a7a78fdb4b7..57dce6081d73 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -615,8 +615,16 @@ struct drm_gem_object {
615 /** Reference count of this object */ 615 /** Reference count of this object */
616 struct kref refcount; 616 struct kref refcount;
617 617
618 /** Handle count of this object. Each handle also holds a reference */ 618 /**
619 atomic_t handle_count; /* number of handles on this object */ 619 * handle_count - gem file_priv handle count of this object
620 *
621 * Each handle also holds a reference. Note that when the handle_count
622 * drops to 0 any global names (e.g. the id in the flink namespace) will
623 * be cleared.
624 *
625 * Protected by dev->object_name_lock.
626 * */
627 unsigned handle_count;
620 628
621 /** Related drm device */ 629 /** Related drm device */
622 struct drm_device *dev; 630 struct drm_device *dev;
@@ -1572,13 +1580,6 @@ int drm_gem_handle_create(struct drm_file *file_priv,
1572 u32 *handlep); 1580 u32 *handlep);
1573int drm_gem_handle_delete(struct drm_file *filp, u32 handle); 1581int drm_gem_handle_delete(struct drm_file *filp, u32 handle);
1574 1582
1575static inline void
1576drm_gem_object_handle_reference(struct drm_gem_object *obj)
1577{
1578 drm_gem_object_reference(obj);
1579 atomic_inc(&obj->handle_count);
1580}
1581
1582void drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj); 1583void drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj);
1583 1584
1584void drm_gem_free_mmap_offset(struct drm_gem_object *obj); 1585void drm_gem_free_mmap_offset(struct drm_gem_object *obj);