diff options
| author | Dave Airlie <airlied@redhat.com> | 2010-09-27 02:17:17 -0400 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2010-09-30 19:17:44 -0400 |
| commit | 29d08b3efddca628b0360411ab2b85f7b1723f48 (patch) | |
| tree | f89a8a3069ebe9828b8a08c4b123f52625bf0bc7 | |
| parent | 130b9851933e6da636502cd85e1ba8f45f862e8c (diff) | |
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>
| -rw-r--r-- | drivers/gpu/drm/drm_gem.c | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_info.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_fb.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fbcon.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_gem.c | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_notifier.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_fb.c | 14 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_gem.c | 4 | ||||
| -rw-r--r-- | include/drm/drmP.h | 18 |
11 files changed, 33 insertions, 34 deletions
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 6fe2cd298c12..f7e61be8430a 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c | |||
| @@ -148,7 +148,7 @@ int drm_gem_object_init(struct drm_device *dev, | |||
| 148 | return -ENOMEM; | 148 | return -ENOMEM; |
| 149 | 149 | ||
| 150 | kref_init(&obj->refcount); | 150 | kref_init(&obj->refcount); |
| 151 | kref_init(&obj->handlecount); | 151 | atomic_set(&obj->handle_count, 0); |
| 152 | obj->size = size; | 152 | obj->size = size; |
| 153 | 153 | ||
| 154 | atomic_inc(&dev->object_count); | 154 | atomic_inc(&dev->object_count); |
| @@ -496,12 +496,8 @@ static void drm_gem_object_ref_bug(struct kref *list_kref) | |||
| 496 | * called before drm_gem_object_free or we'll be touching | 496 | * called before drm_gem_object_free or we'll be touching |
| 497 | * freed memory | 497 | * freed memory |
| 498 | */ | 498 | */ |
| 499 | void | 499 | void drm_gem_object_handle_free(struct drm_gem_object *obj) |
| 500 | drm_gem_object_handle_free(struct kref *kref) | ||
| 501 | { | 500 | { |
| 502 | struct drm_gem_object *obj = container_of(kref, | ||
| 503 | struct drm_gem_object, | ||
| 504 | handlecount); | ||
| 505 | struct drm_device *dev = obj->dev; | 501 | struct drm_device *dev = obj->dev; |
| 506 | 502 | ||
| 507 | /* Remove any name for this object */ | 503 | /* Remove any name for this object */ |
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index 2ef2c7827243..974e970ce3f8 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c | |||
| @@ -255,7 +255,7 @@ int drm_gem_one_name_info(int id, void *ptr, void *data) | |||
| 255 | 255 | ||
| 256 | seq_printf(m, "%6d %8zd %7d %8d\n", | 256 | seq_printf(m, "%6d %8zd %7d %8d\n", |
| 257 | obj->name, obj->size, | 257 | obj->name, obj->size, |
| 258 | atomic_read(&obj->handlecount.refcount), | 258 | atomic_read(&obj->handle_count), |
| 259 | atomic_read(&obj->refcount.refcount)); | 259 | atomic_read(&obj->refcount.refcount)); |
| 260 | return 0; | 260 | return 0; |
| 261 | } | 261 | } |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index cf4ffbee1c00..4cdf74264ee8 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
| @@ -136,14 +136,12 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, | |||
| 136 | return -ENOMEM; | 136 | return -ENOMEM; |
| 137 | 137 | ||
| 138 | ret = drm_gem_handle_create(file_priv, obj, &handle); | 138 | ret = drm_gem_handle_create(file_priv, obj, &handle); |
| 139 | /* drop reference from allocate - handle holds it now */ | ||
| 140 | drm_gem_object_unreference_unlocked(obj); | ||
| 139 | if (ret) { | 141 | if (ret) { |
| 140 | drm_gem_object_unreference_unlocked(obj); | ||
| 141 | return ret; | 142 | return ret; |
| 142 | } | 143 | } |
| 143 | 144 | ||
| 144 | /* Sink the floating reference from kref_init(handlecount) */ | ||
| 145 | drm_gem_object_handle_unreference_unlocked(obj); | ||
| 146 | |||
| 147 | args->handle = handle; | 145 | args->handle = handle; |
| 148 | return 0; | 146 | return 0; |
| 149 | } | 147 | } |
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 7bdc96256bf5..56ad9df2ccb5 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c | |||
| @@ -237,8 +237,10 @@ int intel_fbdev_destroy(struct drm_device *dev, | |||
| 237 | drm_fb_helper_fini(&ifbdev->helper); | 237 | drm_fb_helper_fini(&ifbdev->helper); |
| 238 | 238 | ||
| 239 | drm_framebuffer_cleanup(&ifb->base); | 239 | drm_framebuffer_cleanup(&ifb->base); |
| 240 | if (ifb->obj) | 240 | if (ifb->obj) { |
| 241 | drm_gem_object_handle_unreference(ifb->obj); | ||
| 241 | drm_gem_object_unreference(ifb->obj); | 242 | drm_gem_object_unreference(ifb->obj); |
| 243 | } | ||
| 242 | 244 | ||
| 243 | return 0; | 245 | return 0; |
| 244 | } | 246 | } |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index dbd30b2e43fd..d2047713dc59 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c | |||
| @@ -352,6 +352,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev) | |||
| 352 | 352 | ||
| 353 | if (nouveau_fb->nvbo) { | 353 | if (nouveau_fb->nvbo) { |
| 354 | nouveau_bo_unmap(nouveau_fb->nvbo); | 354 | nouveau_bo_unmap(nouveau_fb->nvbo); |
| 355 | drm_gem_object_handle_unreference_unlocked(nouveau_fb->nvbo->gem); | ||
| 355 | drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); | 356 | drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); |
| 356 | nouveau_fb->nvbo = NULL; | 357 | nouveau_fb->nvbo = NULL; |
| 357 | } | 358 | } |
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index ead7b8fc53fc..19620a6709f5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c | |||
| @@ -167,11 +167,9 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, | |||
| 167 | goto out; | 167 | goto out; |
| 168 | 168 | ||
| 169 | ret = drm_gem_handle_create(file_priv, nvbo->gem, &req->info.handle); | 169 | ret = drm_gem_handle_create(file_priv, nvbo->gem, &req->info.handle); |
| 170 | /* drop reference from allocate - handle holds it now */ | ||
| 171 | drm_gem_object_unreference_unlocked(nvbo->gem); | ||
| 170 | out: | 172 | out: |
| 171 | drm_gem_object_handle_unreference_unlocked(nvbo->gem); | ||
| 172 | |||
| 173 | if (ret) | ||
| 174 | drm_gem_object_unreference_unlocked(nvbo->gem); | ||
| 175 | return ret; | 173 | return ret; |
| 176 | } | 174 | } |
| 177 | 175 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c index 3ec181ff50ce..3c9964a8fbad 100644 --- a/drivers/gpu/drm/nouveau/nouveau_notifier.c +++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c | |||
| @@ -79,6 +79,7 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan) | |||
| 79 | mutex_lock(&dev->struct_mutex); | 79 | mutex_lock(&dev->struct_mutex); |
| 80 | nouveau_bo_unpin(chan->notifier_bo); | 80 | nouveau_bo_unpin(chan->notifier_bo); |
| 81 | mutex_unlock(&dev->struct_mutex); | 81 | mutex_unlock(&dev->struct_mutex); |
| 82 | drm_gem_object_handle_unreference_unlocked(chan->notifier_bo->gem); | ||
| 82 | drm_gem_object_unreference_unlocked(chan->notifier_bo->gem); | 83 | drm_gem_object_unreference_unlocked(chan->notifier_bo->gem); |
| 83 | drm_mm_takedown(&chan->notifier_heap); | 84 | drm_mm_takedown(&chan->notifier_heap); |
| 84 | } | 85 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 7422f274615a..b92d2f2fcbed 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
| @@ -843,8 +843,9 @@ static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) | |||
| 843 | { | 843 | { |
| 844 | struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); | 844 | struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); |
| 845 | 845 | ||
| 846 | if (radeon_fb->obj) | 846 | if (radeon_fb->obj) { |
| 847 | drm_gem_object_unreference_unlocked(radeon_fb->obj); | 847 | drm_gem_object_unreference_unlocked(radeon_fb->obj); |
| 848 | } | ||
| 848 | drm_framebuffer_cleanup(fb); | 849 | drm_framebuffer_cleanup(fb); |
| 849 | kfree(radeon_fb); | 850 | kfree(radeon_fb); |
| 850 | } | 851 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index c74a8b20d941..9cdf6a35bc2c 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c | |||
| @@ -94,8 +94,10 @@ static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj) | |||
| 94 | ret = radeon_bo_reserve(rbo, false); | 94 | ret = radeon_bo_reserve(rbo, false); |
| 95 | if (likely(ret == 0)) { | 95 | if (likely(ret == 0)) { |
| 96 | radeon_bo_kunmap(rbo); | 96 | radeon_bo_kunmap(rbo); |
| 97 | radeon_bo_unpin(rbo); | ||
| 97 | radeon_bo_unreserve(rbo); | 98 | radeon_bo_unreserve(rbo); |
| 98 | } | 99 | } |
| 100 | drm_gem_object_handle_unreference(gobj); | ||
| 99 | drm_gem_object_unreference_unlocked(gobj); | 101 | drm_gem_object_unreference_unlocked(gobj); |
| 100 | } | 102 | } |
| 101 | 103 | ||
| @@ -325,8 +327,6 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb | |||
| 325 | { | 327 | { |
| 326 | struct fb_info *info; | 328 | struct fb_info *info; |
| 327 | struct radeon_framebuffer *rfb = &rfbdev->rfb; | 329 | struct radeon_framebuffer *rfb = &rfbdev->rfb; |
| 328 | struct radeon_bo *rbo; | ||
| 329 | int r; | ||
| 330 | 330 | ||
| 331 | if (rfbdev->helper.fbdev) { | 331 | if (rfbdev->helper.fbdev) { |
| 332 | info = rfbdev->helper.fbdev; | 332 | info = rfbdev->helper.fbdev; |
| @@ -338,14 +338,8 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb | |||
| 338 | } | 338 | } |
| 339 | 339 | ||
| 340 | if (rfb->obj) { | 340 | if (rfb->obj) { |
| 341 | rbo = rfb->obj->driver_private; | 341 | radeonfb_destroy_pinned_object(rfb->obj); |
| 342 | r = radeon_bo_reserve(rbo, false); | 342 | rfb->obj = NULL; |
| 343 | if (likely(r == 0)) { | ||
| 344 | radeon_bo_kunmap(rbo); | ||
| 345 | radeon_bo_unpin(rbo); | ||
| 346 | radeon_bo_unreserve(rbo); | ||
| 347 | } | ||
| 348 | drm_gem_object_unreference_unlocked(rfb->obj); | ||
| 349 | } | 343 | } |
| 350 | drm_fb_helper_fini(&rfbdev->helper); | 344 | drm_fb_helper_fini(&rfbdev->helper); |
| 351 | drm_framebuffer_cleanup(&rfb->base); | 345 | drm_framebuffer_cleanup(&rfb->base); |
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index c578f265b24c..d1e595d91723 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c | |||
| @@ -201,11 +201,11 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data, | |||
| 201 | return r; | 201 | return r; |
| 202 | } | 202 | } |
| 203 | r = drm_gem_handle_create(filp, gobj, &handle); | 203 | r = drm_gem_handle_create(filp, gobj, &handle); |
| 204 | /* drop reference from allocate - handle holds it now */ | ||
| 205 | drm_gem_object_unreference_unlocked(gobj); | ||
| 204 | if (r) { | 206 | if (r) { |
| 205 | drm_gem_object_unreference_unlocked(gobj); | ||
| 206 | return r; | 207 | return r; |
| 207 | } | 208 | } |
| 208 | drm_gem_object_handle_unreference_unlocked(gobj); | ||
| 209 | args->handle = handle; | 209 | args->handle = handle; |
| 210 | return 0; | 210 | return 0; |
| 211 | } | 211 | } |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 774e1d49509b..07e4726a4ee0 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
| @@ -612,7 +612,7 @@ struct drm_gem_object { | |||
| 612 | struct kref refcount; | 612 | struct kref refcount; |
| 613 | 613 | ||
| 614 | /** Handle count of this object. Each handle also holds a reference */ | 614 | /** Handle count of this object. Each handle also holds a reference */ |
| 615 | struct kref handlecount; | 615 | atomic_t handle_count; /* number of handles on this object */ |
| 616 | 616 | ||
| 617 | /** Related drm device */ | 617 | /** Related drm device */ |
| 618 | struct drm_device *dev; | 618 | struct drm_device *dev; |
| @@ -1461,7 +1461,7 @@ struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev, | |||
| 1461 | size_t size); | 1461 | size_t size); |
| 1462 | int drm_gem_object_init(struct drm_device *dev, | 1462 | int drm_gem_object_init(struct drm_device *dev, |
| 1463 | struct drm_gem_object *obj, size_t size); | 1463 | struct drm_gem_object *obj, size_t size); |
| 1464 | void drm_gem_object_handle_free(struct kref *kref); | 1464 | void drm_gem_object_handle_free(struct drm_gem_object *obj); |
| 1465 | void drm_gem_vm_open(struct vm_area_struct *vma); | 1465 | void drm_gem_vm_open(struct vm_area_struct *vma); |
| 1466 | void drm_gem_vm_close(struct vm_area_struct *vma); | 1466 | void drm_gem_vm_close(struct vm_area_struct *vma); |
| 1467 | int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); | 1467 | int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); |
| @@ -1496,7 +1496,7 @@ static inline void | |||
| 1496 | drm_gem_object_handle_reference(struct drm_gem_object *obj) | 1496 | drm_gem_object_handle_reference(struct drm_gem_object *obj) |
| 1497 | { | 1497 | { |
| 1498 | drm_gem_object_reference(obj); | 1498 | drm_gem_object_reference(obj); |
| 1499 | kref_get(&obj->handlecount); | 1499 | atomic_inc(&obj->handle_count); |
| 1500 | } | 1500 | } |
| 1501 | 1501 | ||
| 1502 | static inline void | 1502 | static inline void |
| @@ -1505,12 +1505,15 @@ drm_gem_object_handle_unreference(struct drm_gem_object *obj) | |||
| 1505 | if (obj == NULL) | 1505 | if (obj == NULL) |
| 1506 | return; | 1506 | return; |
| 1507 | 1507 | ||
| 1508 | if (atomic_read(&obj->handle_count) == 0) | ||
| 1509 | return; | ||
| 1508 | /* | 1510 | /* |
| 1509 | * Must bump handle count first as this may be the last | 1511 | * Must bump handle count first as this may be the last |
| 1510 | * ref, in which case the object would disappear before we | 1512 | * ref, in which case the object would disappear before we |
| 1511 | * checked for a name | 1513 | * checked for a name |
| 1512 | */ | 1514 | */ |
| 1513 | kref_put(&obj->handlecount, drm_gem_object_handle_free); | 1515 | if (atomic_dec_and_test(&obj->handle_count)) |
| 1516 | drm_gem_object_handle_free(obj); | ||
| 1514 | drm_gem_object_unreference(obj); | 1517 | drm_gem_object_unreference(obj); |
| 1515 | } | 1518 | } |
| 1516 | 1519 | ||
| @@ -1520,12 +1523,17 @@ drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj) | |||
| 1520 | if (obj == NULL) | 1523 | if (obj == NULL) |
| 1521 | return; | 1524 | return; |
| 1522 | 1525 | ||
| 1526 | if (atomic_read(&obj->handle_count) == 0) | ||
| 1527 | return; | ||
| 1528 | |||
| 1523 | /* | 1529 | /* |
| 1524 | * Must bump handle count first as this may be the last | 1530 | * Must bump handle count first as this may be the last |
| 1525 | * ref, in which case the object would disappear before we | 1531 | * ref, in which case the object would disappear before we |
| 1526 | * checked for a name | 1532 | * checked for a name |
| 1527 | */ | 1533 | */ |
| 1528 | kref_put(&obj->handlecount, drm_gem_object_handle_free); | 1534 | |
| 1535 | if (atomic_dec_and_test(&obj->handle_count)) | ||
| 1536 | drm_gem_object_handle_free(obj); | ||
| 1529 | drm_gem_object_unreference_unlocked(obj); | 1537 | drm_gem_object_unreference_unlocked(obj); |
| 1530 | } | 1538 | } |
| 1531 | 1539 | ||
