Skip to content

Commit

Permalink
mm: kmemleak: avoid false negatives on vmalloc'ed objects
Browse files Browse the repository at this point in the history
commit 7f88f88 upstream.

Commit 248ac0e ("mm/vmalloc: remove guard page from between vmap
blocks") had the side effect of making vmap_area.va_end member point to
the next vmap_area.va_start.  This was creating an artificial reference
to vmalloc'ed objects and kmemleak was rarely reporting vmalloc() leaks.

This patch marks the vmap_area containing pointers explicitly and
reduces the min ref_count to 2 as vm_struct still contains a reference
to the vmalloc'ed object.  The kmemleak add_scan_area() function has
been improved to allow a SIZE_MAX argument covering the rest of the
object (for simpler calling sites).

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
[hq: Backported to 3.4: Adjust context]
Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Catalin Marinas authored and Greg Kroah-Hartman committed Jul 31, 2014
1 parent b06b5c6 commit 7e2e611
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 5 deletions.
4 changes: 3 additions & 1 deletion mm/kmemleak.c
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,9 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp)
}

spin_lock_irqsave(&object->lock, flags);
if (ptr + size > object->pointer + object->size) {
if (size == SIZE_MAX) {
size = object->pointer + object->size - ptr;
} else if (ptr + size > object->pointer + object->size) {
kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr);
dump_object_info(object);
kmem_cache_free(scan_area_cache, area);
Expand Down
14 changes: 10 additions & 4 deletions mm/vmalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,12 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
if (unlikely(!va))
return ERR_PTR(-ENOMEM);

/*
* Only scan the relevant parts containing pointers to other objects
* to avoid false negatives.
*/
kmemleak_scan_area(&va->rb_node, SIZE_MAX, gfp_mask & GFP_RECLAIM_MASK);

retry:
spin_lock(&vmap_area_lock);
/*
Expand Down Expand Up @@ -1669,11 +1675,11 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,
insert_vmalloc_vmlist(area);

/*
* A ref_count = 3 is needed because the vm_struct and vmap_area
* structures allocated in the __get_vm_area_node() function contain
* references to the virtual address of the vmalloc'ed block.
* A ref_count = 2 is needed because vm_struct allocated in
* __get_vm_area_node() contains a reference to the virtual address of
* the vmalloc'ed block.
*/
kmemleak_alloc(addr, real_size, 3, gfp_mask);
kmemleak_alloc(addr, real_size, 2, gfp_mask);

return addr;

Expand Down

0 comments on commit 7e2e611

Please sign in to comment.