aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-09-30 04:10:26 -0400
committerDave Airlie <airlied@redhat.com>2010-10-01 07:08:45 -0400
commit39b4d07aa3583ceefe73622841303a0a3e942ca1 (patch)
treed42f6e782f331b1d967f50ca3a02b9e51ea88515
parent29d08b3efddca628b0360411ab2b85f7b1723f48 (diff)
drm: Hold the mutex when dropping the last GEM reference (v2)
In order to be fully threadsafe we need to check that the drm_gem_object refcount is still 0 after acquiring the mutex in order to call the free function. Otherwise, we may encounter scenarios like: Thread A: Thread B: drm_gem_close unreference_unlocked kref_put mutex_lock ... i915_gem_evict ... kref_get -> BUG ... i915_gem_unbind ... kref_put ... i915_gem_object_free ... mutex_unlock mutex_lock i915_gem_object_free -> BUG i915_gem_object_unbind kfree mutex_unlock Note that no driver is currently using the free_unlocked vfunc and it is scheduled for removal, hasten that process. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=30454 Reported-and-Tested-by: Magnus Kessler <Magnus.Kessler@gmx.net> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: stable@kernel.org Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_gem.c22
-rw-r--r--include/drm/drmP.h10
2 files changed, 6 insertions, 26 deletions
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index f7e61be8430a..5663d2719063 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -462,28 +462,6 @@ drm_gem_object_free(struct kref *kref)
462} 462}
463EXPORT_SYMBOL(drm_gem_object_free); 463EXPORT_SYMBOL(drm_gem_object_free);
464 464
465/**
466 * Called after the last reference to the object has been lost.
467 * Must be called without holding struct_mutex
468 *
469 * Frees the object
470 */
471void
472drm_gem_object_free_unlocked(struct kref *kref)
473{
474 struct drm_gem_object *obj = (struct drm_gem_object *) kref;
475 struct drm_device *dev = obj->dev;
476
477 if (dev->driver->gem_free_object_unlocked != NULL)
478 dev->driver->gem_free_object_unlocked(obj);
479 else if (dev->driver->gem_free_object != NULL) {
480 mutex_lock(&dev->struct_mutex);
481 dev->driver->gem_free_object(obj);
482 mutex_unlock(&dev->struct_mutex);
483 }
484}
485EXPORT_SYMBOL(drm_gem_object_free_unlocked);
486
487static void drm_gem_object_ref_bug(struct kref *list_kref) 465static void drm_gem_object_ref_bug(struct kref *list_kref)
488{ 466{
489 BUG(); 467 BUG();
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 07e4726a4ee0..4c9461a4f9e6 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -808,7 +808,6 @@ struct drm_driver {
808 */ 808 */
809 int (*gem_init_object) (struct drm_gem_object *obj); 809 int (*gem_init_object) (struct drm_gem_object *obj);
810 void (*gem_free_object) (struct drm_gem_object *obj); 810 void (*gem_free_object) (struct drm_gem_object *obj);
811 void (*gem_free_object_unlocked) (struct drm_gem_object *obj);
812 811
813 /* vga arb irq handler */ 812 /* vga arb irq handler */
814 void (*vgaarb_irq)(struct drm_device *dev, bool state); 813 void (*vgaarb_irq)(struct drm_device *dev, bool state);
@@ -1456,7 +1455,6 @@ int drm_gem_init(struct drm_device *dev);
1456void drm_gem_destroy(struct drm_device *dev); 1455void drm_gem_destroy(struct drm_device *dev);
1457void drm_gem_object_release(struct drm_gem_object *obj); 1456void drm_gem_object_release(struct drm_gem_object *obj);
1458void drm_gem_object_free(struct kref *kref); 1457void drm_gem_object_free(struct kref *kref);
1459void drm_gem_object_free_unlocked(struct kref *kref);
1460struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev, 1458struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev,
1461 size_t size); 1459 size_t size);
1462int drm_gem_object_init(struct drm_device *dev, 1460int drm_gem_object_init(struct drm_device *dev,
@@ -1484,8 +1482,12 @@ drm_gem_object_unreference(struct drm_gem_object *obj)
1484static inline void 1482static inline void
1485drm_gem_object_unreference_unlocked(struct drm_gem_object *obj) 1483drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
1486{ 1484{
1487 if (obj != NULL) 1485 if (obj != NULL) {
1488 kref_put(&obj->refcount, drm_gem_object_free_unlocked); 1486 struct drm_device *dev = obj->dev;
1487 mutex_lock(&dev->struct_mutex);
1488 kref_put(&obj->refcount, drm_gem_object_free);
1489 mutex_unlock(&dev->struct_mutex);
1490 }
1489} 1491}
1490 1492
1491int drm_gem_handle_create(struct drm_file *file_priv, 1493int drm_gem_handle_create(struct drm_file *file_priv,