drm/gem: handlecount isn't really a kref so don't make it one.

There were lots of places being inconsistent since handle count
looked like a kref but it really wasn't.

Fix this my just making handle count an atomic on the object,
and have it increase the normal object kref.

Now i915/radeon/nouveau drivers can drop the normal reference on
userspace object creation, and have the handle hold it.

This patch fixes a memory leak or corruption on unload, because
the driver had no way of knowing if a handle had been actually
added for this object, and the fbcon object needed to know this
to clean itself up properly.

Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Dave Airlie
2010-09-27 16:17:17 +10:00
parent 130b985193
commit 29d08b3efd
11 changed files with 33 additions and 34 deletions

View File

@@ -612,7 +612,7 @@ struct drm_gem_object {
struct kref refcount;
/** Handle count of this object. Each handle also holds a reference */
struct kref handlecount;
atomic_t handle_count; /* number of handles on this object */
/** Related drm device */
struct drm_device *dev;
@@ -1461,7 +1461,7 @@ struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev,
size_t size);
int drm_gem_object_init(struct drm_device *dev,
struct drm_gem_object *obj, size_t size);
void drm_gem_object_handle_free(struct kref *kref);
void drm_gem_object_handle_free(struct drm_gem_object *obj);
void drm_gem_vm_open(struct vm_area_struct *vma);
void drm_gem_vm_close(struct vm_area_struct *vma);
int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
@@ -1496,7 +1496,7 @@ static inline void
drm_gem_object_handle_reference(struct drm_gem_object *obj)
{
drm_gem_object_reference(obj);
kref_get(&obj->handlecount);
atomic_inc(&obj->handle_count);
}
static inline void
@@ -1505,12 +1505,15 @@ drm_gem_object_handle_unreference(struct drm_gem_object *obj)
if (obj == NULL)
return;
if (atomic_read(&obj->handle_count) == 0)
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);
if (atomic_dec_and_test(&obj->handle_count))
drm_gem_object_handle_free(obj);
drm_gem_object_unreference(obj);
}
@@ -1520,12 +1523,17 @@ drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj)
if (obj == NULL)
return;
if (atomic_read(&obj->handle_count) == 0)
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);
if (atomic_dec_and_test(&obj->handle_count))
drm_gem_object_handle_free(obj);
drm_gem_object_unreference_unlocked(obj);
}