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:
@@ -410,6 +410,13 @@ config DEBUG_KMEMLEAK_TEST
|
|||||||
|
|
||||||
If unsure, say N.
|
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
|
config DEBUG_PREEMPT
|
||||||
bool "Debug preemptible kernel"
|
bool "Debug preemptible kernel"
|
||||||
depends on DEBUG_KERNEL && PREEMPT && TRACE_IRQFLAGS_SUPPORT
|
depends on DEBUG_KERNEL && PREEMPT && TRACE_IRQFLAGS_SUPPORT
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
#include <linux/highmem.h>
|
#include <linux/highmem.h>
|
||||||
|
#include <linux/kmemleak.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sg_next - return the next scatterlist entry in a list
|
* 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)
|
static struct scatterlist *sg_kmalloc(unsigned int nents, gfp_t gfp_mask)
|
||||||
{
|
{
|
||||||
if (nents == SG_MAX_SINGLE_ALLOC)
|
if (nents == SG_MAX_SINGLE_ALLOC) {
|
||||||
return (struct scatterlist *) __get_free_page(gfp_mask);
|
/*
|
||||||
else
|
* 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);
|
return kmalloc(nents * sizeof(struct scatterlist), gfp_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sg_kfree(struct scatterlist *sg, unsigned int nents)
|
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);
|
free_page((unsigned long) sg);
|
||||||
else
|
} else
|
||||||
kfree(sg);
|
kfree(sg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
100
mm/kmemleak.c
100
mm/kmemleak.c
@@ -211,6 +211,9 @@ static signed long jiffies_scan_wait;
|
|||||||
static int kmemleak_stack_scan = 1;
|
static int kmemleak_stack_scan = 1;
|
||||||
/* protects the memory scanning, parameters and debug/kmemleak file access */
|
/* protects the memory scanning, parameters and debug/kmemleak file access */
|
||||||
static DEFINE_MUTEX(scan_mutex);
|
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
|
* 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,
|
object = prio_tree_entry(node, struct kmemleak_object,
|
||||||
tree_node);
|
tree_node);
|
||||||
if (!alias && object->pointer != ptr) {
|
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;
|
object = NULL;
|
||||||
}
|
}
|
||||||
} else
|
} 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.
|
* reported as a leak. This is used in general to mark a false positive.
|
||||||
*/
|
*/
|
||||||
static void make_gray_object(unsigned long ptr)
|
static void make_gray_object(unsigned long ptr)
|
||||||
@@ -838,10 +843,19 @@ out:
|
|||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Memory allocation function callback. This function is called from the
|
* kmemleak_alloc - register a newly allocated object
|
||||||
* kernel allocators when a new block is allocated (kmem_cache_alloc, kmalloc,
|
* @ptr: pointer to beginning of the object
|
||||||
* vmalloc etc.).
|
* @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,
|
void __ref kmemleak_alloc(const void *ptr, size_t size, int min_count,
|
||||||
gfp_t gfp)
|
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);
|
EXPORT_SYMBOL_GPL(kmemleak_alloc);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Memory freeing function callback. This function is called from the kernel
|
* kmemleak_free - unregister a previously registered object
|
||||||
* allocators when a block is freed (kmem_cache_free, kfree, vfree etc.).
|
* @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)
|
void __ref kmemleak_free(const void *ptr)
|
||||||
{
|
{
|
||||||
@@ -870,9 +887,14 @@ void __ref kmemleak_free(const void *ptr)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(kmemleak_free);
|
EXPORT_SYMBOL_GPL(kmemleak_free);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Partial memory freeing function callback. This function is usually called
|
* kmemleak_free_part - partially unregister a previously registered object
|
||||||
* from bootmem allocator when (part of) a memory block is freed.
|
* @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)
|
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);
|
EXPORT_SYMBOL_GPL(kmemleak_free_part);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Mark an already allocated memory block as a false positive. This will cause
|
* kmemleak_not_leak - mark an allocated object as false positive
|
||||||
* the block to no longer be reported as leak and always be scanned.
|
* @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)
|
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);
|
EXPORT_SYMBOL(kmemleak_not_leak);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Ignore a memory block. This is usually done when it is known that the
|
* kmemleak_ignore - ignore an allocated object
|
||||||
* corresponding block is not a leak and does not contain any references to
|
* @ptr: pointer to beginning of the object
|
||||||
* other allocated memory blocks.
|
*
|
||||||
|
* 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)
|
void __ref kmemleak_ignore(const void *ptr)
|
||||||
{
|
{
|
||||||
@@ -916,8 +945,16 @@ void __ref kmemleak_ignore(const void *ptr)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(kmemleak_ignore);
|
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)
|
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);
|
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)
|
void __ref kmemleak_no_scan(const void *ptr)
|
||||||
{
|
{
|
||||||
@@ -1602,7 +1645,9 @@ static int kmemleak_boot_config(char *str)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (strcmp(str, "off") == 0)
|
if (strcmp(str, "off") == 0)
|
||||||
kmemleak_disable();
|
kmemleak_disable();
|
||||||
else if (strcmp(str, "on") != 0)
|
else if (strcmp(str, "on") == 0)
|
||||||
|
kmemleak_skip_disable = 1;
|
||||||
|
else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1616,6 +1661,13 @@ void __init kmemleak_init(void)
|
|||||||
int i;
|
int i;
|
||||||
unsigned long flags;
|
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_min_age = msecs_to_jiffies(MSECS_MIN_AGE);
|
||||||
jiffies_scan_wait = msecs_to_jiffies(SECS_SCAN_WAIT * 1000);
|
jiffies_scan_wait = msecs_to_jiffies(SECS_SCAN_WAIT * 1000);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user