drm: Free the idr layers before calling idr_destroy()
authorChris Wilson <chris@chris-wilson.co.uk>
Sat, 24 Jul 2010 21:28:25 +0000 (22:28 +0100)
committerDave Airlie <airlied@redhat.com>
Mon, 2 Aug 2010 00:13:56 +0000 (10:13 +1000)
/* A typical clean-up sequence for objects stored in an idr tree, will
 * use idr_for_each() to free all objects, if necessary, then
 * idr_remove_all() to remove all ids, and idr_destroy() to free
 * up the cached idr_layers.
 */

We were missing the vital idr_rmove_all() step and so were leaking
the used layers for every dri client:

unreferenced object 0xf32133c0 (size 148):
  comm "plymouthd", pid 131, jiffies 4294678490 (age 2308.030s)
  hex dump (first 32 bytes):
    04 00 00 00 00 00 00 00 00 00 00 00 00 40 19 f3  .............@..
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  backtrace:
    [<c04e5657>] create_object+0x124/0x1f1
    [<c07cf100>] kmemleak_alloc+0x4c/0x90
    [<c04db6a9>] kmem_cache_alloc+0xee/0x13c
    [<c05c3d25>] idr_pre_get+0x24/0x61
    [<f8315c9c>] drm_gem_handle_create+0x27/0x7f [drm]
    [<f89925b2>] i915_gem_create_ioctl+0x4f/0x71 [i915]
    [<f83148ac>] drm_ioctl+0x272/0x356 [drm]
    [<c04f27c4>] vfs_ioctl+0x33/0x91
    [<c04f31cf>] do_vfs_ioctl+0x46b/0x496
    [<c04f3240>] sys_ioctl+0x46/0x66
    [<c040325f>] sysenter_do_call+0x12/0x38
    [<ffffffff>] 0xffffffff

Fixes https://bugzilla.kernel.org/show_bug.cgi?id=15803

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_gem.c

index 510bc87d98f6f991e93e31d74affe90fd9986792..b5a51686f492edce08e59bc0bb9fb391a5faae34 100644 (file)
@@ -335,6 +335,7 @@ static void __exit drm_core_exit(void)
 
        unregister_chrdev(DRM_MAJOR, "drm");
 
+       idr_remove_all(&drm_minors_idr);
        idr_destroy(&drm_minors_idr);
 }
 
index 8601b72b6f26694def3cc4329158b9c27f770c7a..4f1b8671448921dc74b4a7e201d2a03309f495d5 100644 (file)
@@ -429,6 +429,7 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
        idr_for_each(&file_private->object_idr,
                     &drm_gem_object_release_handle, NULL);
 
+       idr_remove_all(&file_private->object_idr);
        idr_destroy(&file_private->object_idr);
 }