drm: introduce drm_gem_object_[handle_]unreference_unlocked
authorLuca Barbieri <luca@luca-barbieri.com>
Tue, 9 Feb 2010 05:49:11 +0000 (05:49 +0000)
committerDave Airlie <airlied@redhat.com>
Thu, 11 Feb 2010 04:21:24 +0000 (14:21 +1000)
This patch introduces the drm_gem_object_unreference_unlocked
and drm_gem_object_handle_unreference_unlocked functions that
do not require holding struct_mutex.

drm_gem_object_unreference_unlocked calls the new
->gem_free_object_unlocked entry point if available, and
otherwise just takes struct_mutex and just calls ->gem_free_object

Signed-off-by: Luca Barbieri <luca@luca-barbieri.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/drm_gem.c
include/drm/drmP.h

index 8bf3770f294e12feb562d046a5de4ed281b9ce45..4018b3bfc72e49e507b282a218602ef4048a1714 100644 (file)
@@ -411,8 +411,19 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
        mutex_unlock(&dev->struct_mutex);
 }
 
+static void
+drm_gem_object_free_common(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       fput(obj->filp);
+       atomic_dec(&dev->object_count);
+       atomic_sub(obj->size, &dev->object_memory);
+       kfree(obj);
+}
+
 /**
  * Called after the last reference to the object has been lost.
+ * Must be called holding struct_ mutex
  *
  * Frees the object
  */
@@ -427,13 +438,39 @@ drm_gem_object_free(struct kref *kref)
        if (dev->driver->gem_free_object != NULL)
                dev->driver->gem_free_object(obj);
 
-       fput(obj->filp);
-       atomic_dec(&dev->object_count);
-       atomic_sub(obj->size, &dev->object_memory);
-       kfree(obj);
+       drm_gem_object_free_common(obj);
 }
 EXPORT_SYMBOL(drm_gem_object_free);
 
+/**
+ * Called after the last reference to the object has been lost.
+ * Must be called without holding struct_mutex
+ *
+ * Frees the object
+ */
+void
+drm_gem_object_free_unlocked(struct kref *kref)
+{
+       struct drm_gem_object *obj = (struct drm_gem_object *) kref;
+       struct drm_device *dev = obj->dev;
+
+       if (dev->driver->gem_free_object_unlocked != NULL)
+               dev->driver->gem_free_object_unlocked(obj);
+       else if (dev->driver->gem_free_object != NULL) {
+               mutex_lock(&dev->struct_mutex);
+               dev->driver->gem_free_object(obj);
+               mutex_unlock(&dev->struct_mutex);
+       }
+
+       drm_gem_object_free_common(obj);
+}
+EXPORT_SYMBOL(drm_gem_object_free_unlocked);
+
+static void drm_gem_object_ref_bug(struct kref *list_kref)
+{
+       BUG();
+}
+
 /**
  * Called after the last handle to the object has been closed
  *
@@ -458,8 +495,10 @@ drm_gem_object_handle_free(struct kref *kref)
                /*
                 * The object name held a reference to this object, drop
                 * that now.
+               *
+               * This cannot be the last reference, since the handle holds one too.
                 */
-               drm_gem_object_unreference(obj);
+               kref_put(&obj->refcount, drm_gem_object_ref_bug);
        } else
                spin_unlock(&dev->object_name_lock);
 
index ffac157fb5b2958aa33df80184a535a5fb5b9af6..4a3c4e441027be39da3d37b8a817ff9f918661dd 100644 (file)
@@ -801,6 +801,7 @@ struct drm_driver {
         */
        int (*gem_init_object) (struct drm_gem_object *obj);
        void (*gem_free_object) (struct drm_gem_object *obj);
+       void (*gem_free_object_unlocked) (struct drm_gem_object *obj);
 
        /* vga arb irq handler */
        void (*vgaarb_irq)(struct drm_device *dev, bool state);
@@ -1427,6 +1428,7 @@ extern void drm_sysfs_connector_remove(struct drm_connector *connector);
 int drm_gem_init(struct drm_device *dev);
 void drm_gem_destroy(struct drm_device *dev);
 void drm_gem_object_free(struct kref *kref);
+void drm_gem_object_free_unlocked(struct kref *kref);
 struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev,
                                            size_t size);
 void drm_gem_object_handle_free(struct kref *kref);
@@ -1443,10 +1445,15 @@ drm_gem_object_reference(struct drm_gem_object *obj)
 static inline void
 drm_gem_object_unreference(struct drm_gem_object *obj)
 {
-       if (obj == NULL)
-               return;
+       if (obj != NULL)
+               kref_put(&obj->refcount, drm_gem_object_free);
+}
 
-       kref_put(&obj->refcount, drm_gem_object_free);
+static inline void
+drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
+{
+       if (obj != NULL)
+               kref_put(&obj->refcount, drm_gem_object_free_unlocked);
 }
 
 int drm_gem_handle_create(struct drm_file *file_priv,
@@ -1475,6 +1482,21 @@ drm_gem_object_handle_unreference(struct drm_gem_object *obj)
        drm_gem_object_unreference(obj);
 }
 
+static inline void
+drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj)
+{
+       if (obj == NULL)
+               return;
+
+       /*
+       * Must bump handle count first as this may be the last
+       * ref, in which case the object would disappear before we
+       * checked for a name
+       */
+       kref_put(&obj->handlecount, drm_gem_object_handle_free);
+       drm_gem_object_unreference_unlocked(obj);
+}
+
 struct drm_gem_object *drm_gem_object_lookup(struct drm_device *dev,
                                             struct drm_file *filp,
                                             u32 handle);