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:
Коммит
4c619407b0
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
100
mm/kmemleak.c
100
mm/kmemleak.c
|
@ -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 @@ out:
|
|||
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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче