Merge branch 'kmemleak' of git://git.kernel.org/pub/scm/linux/kernel/git/cmarinas/linux-2.6-cm

* 'kmemleak' of git://git.kernel.org/pub/scm/linux/kernel/git/cmarinas/linux-2.6-cm:
  kmemleak: Fix typo in the comment
  lib/scatterlist: Hook sg_kmalloc into kmemleak (v2)
  kmemleak: Add DocBook style comments to kmemleak.c
  kmemleak: Introduce a default off mode for kmemleak
  kmemleak: Show more information for objects found by alias
This commit is contained in:
Linus Torvalds 2010-08-10 13:58:11 -07:00
commit 4c619407b0
3 changed files with 101 additions and 29 deletions

View file

@ -410,6 +410,13 @@ config DEBUG_KMEMLEAK_TEST
If unsure, say N.
config DEBUG_KMEMLEAK_DEFAULT_OFF
bool "Default kmemleak to off"
depends on DEBUG_KMEMLEAK
help
Say Y here to disable kmemleak by default. It can then be enabled
on the command line via kmemleak=on.
config DEBUG_PREEMPT
bool "Debug preemptible kernel"
depends on DEBUG_KERNEL && PREEMPT && TRACE_IRQFLAGS_SUPPORT

View file

@ -10,6 +10,7 @@
#include <linux/slab.h>
#include <linux/scatterlist.h>
#include <linux/highmem.h>
#include <linux/kmemleak.h>
/**
* sg_next - return the next scatterlist entry in a list
@ -115,17 +116,29 @@ EXPORT_SYMBOL(sg_init_one);
*/
static struct scatterlist *sg_kmalloc(unsigned int nents, gfp_t gfp_mask)
{
if (nents == SG_MAX_SINGLE_ALLOC)
return (struct scatterlist *) __get_free_page(gfp_mask);
else
if (nents == SG_MAX_SINGLE_ALLOC) {
/*
* Kmemleak doesn't track page allocations as they are not
* commonly used (in a raw form) for kernel data structures.
* As we chain together a list of pages and then a normal
* kmalloc (tracked by kmemleak), in order to for that last
* allocation not to become decoupled (and thus a
* false-positive) we need to inform kmemleak of all the
* intermediate allocations.
*/
void *ptr = (void *) __get_free_page(gfp_mask);
kmemleak_alloc(ptr, PAGE_SIZE, 1, gfp_mask);
return ptr;
} else
return kmalloc(nents * sizeof(struct scatterlist), gfp_mask);
}
static void sg_kfree(struct scatterlist *sg, unsigned int nents)
{
if (nents == SG_MAX_SINGLE_ALLOC)
if (nents == SG_MAX_SINGLE_ALLOC) {
kmemleak_free(sg);
free_page((unsigned long) sg);
else
} else
kfree(sg);
}

View file

@ -211,6 +211,9 @@ static signed long jiffies_scan_wait;
static int kmemleak_stack_scan = 1;
/* protects the memory scanning, parameters and debug/kmemleak file access */
static DEFINE_MUTEX(scan_mutex);
/* setting kmemleak=on, will set this var, skipping the disable */
static int kmemleak_skip_disable;
/*
* Early object allocation/freeing logging. Kmemleak is initialized after the
@ -398,7 +401,9 @@ static struct kmemleak_object *lookup_object(unsigned long ptr, int alias)
object = prio_tree_entry(node, struct kmemleak_object,
tree_node);
if (!alias && object->pointer != ptr) {
kmemleak_warn("Found object by alias");
pr_warning("Found object by alias at 0x%08lx\n", ptr);
dump_stack();
dump_object_info(object);
object = NULL;
}
} else
@ -695,7 +700,7 @@ static void paint_ptr(unsigned long ptr, int color)
}
/*
* Make a object permanently as gray-colored so that it can no longer be
* Mark an object permanently as gray-colored so that it can no longer be
* reported as a leak. This is used in general to mark a false positive.
*/
static void make_gray_object(unsigned long ptr)
@ -838,10 +843,19 @@ static void early_alloc(struct early_log *log)
rcu_read_unlock();
}
/*
* Memory allocation function callback. This function is called from the
* kernel allocators when a new block is allocated (kmem_cache_alloc, kmalloc,
* vmalloc etc.).
/**
* kmemleak_alloc - register a newly allocated object
* @ptr: pointer to beginning of the object
* @size: size of the object
* @min_count: minimum number of references to this object. If during memory
* scanning a number of references less than @min_count is found,
* the object is reported as a memory leak. If @min_count is 0,
* the object is never reported as a leak. If @min_count is -1,
* the object is ignored (not scanned and not reported as a leak)
* @gfp: kmalloc() flags used for kmemleak internal memory allocations
*
* This function is called from the kernel allocators when a new object
* (memory block) is allocated (kmem_cache_alloc, kmalloc, vmalloc etc.).
*/
void __ref kmemleak_alloc(const void *ptr, size_t size, int min_count,
gfp_t gfp)
@ -855,9 +869,12 @@ void __ref kmemleak_alloc(const void *ptr, size_t size, int min_count,
}
EXPORT_SYMBOL_GPL(kmemleak_alloc);
/*
* Memory freeing function callback. This function is called from the kernel
* allocators when a block is freed (kmem_cache_free, kfree, vfree etc.).
/**
* kmemleak_free - unregister a previously registered object
* @ptr: pointer to beginning of the object
*
* This function is called from the kernel allocators when an object (memory
* block) is freed (kmem_cache_free, kfree, vfree etc.).
*/
void __ref kmemleak_free(const void *ptr)
{
@ -870,9 +887,14 @@ void __ref kmemleak_free(const void *ptr)
}
EXPORT_SYMBOL_GPL(kmemleak_free);
/*
* Partial memory freeing function callback. This function is usually called
* from bootmem allocator when (part of) a memory block is freed.
/**
* kmemleak_free_part - partially unregister a previously registered object
* @ptr: pointer to the beginning or inside the object. This also
* represents the start of the range to be freed
* @size: size to be unregistered
*
* This function is called when only a part of a memory block is freed
* (usually from the bootmem allocator).
*/
void __ref kmemleak_free_part(const void *ptr, size_t size)
{
@ -885,9 +907,12 @@ void __ref kmemleak_free_part(const void *ptr, size_t size)
}
EXPORT_SYMBOL_GPL(kmemleak_free_part);
/*
* Mark an already allocated memory block as a false positive. This will cause
* the block to no longer be reported as leak and always be scanned.
/**
* kmemleak_not_leak - mark an allocated object as false positive
* @ptr: pointer to beginning of the object
*
* Calling this function on an object will cause the memory block to no longer
* be reported as leak and always be scanned.
*/
void __ref kmemleak_not_leak(const void *ptr)
{
@ -900,10 +925,14 @@ void __ref kmemleak_not_leak(const void *ptr)
}
EXPORT_SYMBOL(kmemleak_not_leak);
/*
* Ignore a memory block. This is usually done when it is known that the
* corresponding block is not a leak and does not contain any references to
* other allocated memory blocks.
/**
* kmemleak_ignore - ignore an allocated object
* @ptr: pointer to beginning of the object
*
* Calling this function on an object will cause the memory block to be
* ignored (not scanned and not reported as a leak). This is usually done when
* it is known that the corresponding block is not a leak and does not contain
* any references to other allocated memory blocks.
*/
void __ref kmemleak_ignore(const void *ptr)
{
@ -916,8 +945,16 @@ void __ref kmemleak_ignore(const void *ptr)
}
EXPORT_SYMBOL(kmemleak_ignore);
/*
* Limit the range to be scanned in an allocated memory block.
/**
* kmemleak_scan_area - limit the range to be scanned in an allocated object
* @ptr: pointer to beginning or inside the object. This also
* represents the start of the scan area
* @size: size of the scan area
* @gfp: kmalloc() flags used for kmemleak internal memory allocations
*
* This function is used when it is known that only certain parts of an object
* contain references to other objects. Kmemleak will only scan these areas
* reducing the number false negatives.
*/
void __ref kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp)
{
@ -930,8 +967,14 @@ void __ref kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp)
}
EXPORT_SYMBOL(kmemleak_scan_area);
/*
* Inform kmemleak not to scan the given memory block.
/**
* kmemleak_no_scan - do not scan an allocated object
* @ptr: pointer to beginning of the object
*
* This function notifies kmemleak not to scan the given memory block. Useful
* in situations where it is known that the given object does not contain any
* references to other objects. Kmemleak will not scan such objects reducing
* the number of false negatives.
*/
void __ref kmemleak_no_scan(const void *ptr)
{
@ -1602,7 +1645,9 @@ static int kmemleak_boot_config(char *str)
return -EINVAL;
if (strcmp(str, "off") == 0)
kmemleak_disable();
else if (strcmp(str, "on") != 0)
else if (strcmp(str, "on") == 0)
kmemleak_skip_disable = 1;
else
return -EINVAL;
return 0;
}
@ -1616,6 +1661,13 @@ void __init kmemleak_init(void)
int i;
unsigned long flags;
#ifdef CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF
if (!kmemleak_skip_disable) {
kmemleak_disable();
return;
}
#endif
jiffies_min_age = msecs_to_jiffies(MSECS_MIN_AGE);
jiffies_scan_wait = msecs_to_jiffies(SECS_SCAN_WAIT * 1000);