Commit 1b195b17 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'kmemleak' of git://linux-arm.org/linux-2.6

* 'kmemleak' of git://linux-arm.org/linux-2.6:
  kmemleak: Improve the "Early log buffer exceeded" error message
  kmemleak: fix sparse warning for static declarations
  kmemleak: fix sparse warning over overshadowed flags
  kmemleak: move common painting code together
  kmemleak: add clear command support
  kmemleak: use bool for true/false questions
  kmemleak: Do no create the clean-up thread during kmemleak_disable()
  kmemleak: Scan all thread stacks
  kmemleak: Don't scan uninitialized memory when kmemcheck is enabled
  kmemleak: Ignore the aperture memory hole on x86_64
  kmemleak: Printing of the objects hex dump
  kmemleak: Do not report alloc_bootmem blocks as leaks
  kmemleak: Save the stack trace for early allocations
  kmemleak: Mark the early log buffer as __initdata
  kmemleak: Dump object information on request
  kmemleak: Allow rescheduling during an object scanning
parents 2490138c addd72c1
...@@ -27,6 +27,13 @@ To trigger an intermediate memory scan: ...@@ -27,6 +27,13 @@ To trigger an intermediate memory scan:
# echo scan > /sys/kernel/debug/kmemleak # echo scan > /sys/kernel/debug/kmemleak
To clear the list of all current possible memory leaks:
# echo clear > /sys/kernel/debug/kmemleak
New leaks will then come up upon reading /sys/kernel/debug/kmemleak
again.
Note that the orphan objects are listed in the order they were allocated Note that the orphan objects are listed in the order they were allocated
and one object at the beginning of the list may cause other subsequent and one object at the beginning of the list may cause other subsequent
objects to be reported as orphan. objects to be reported as orphan.
...@@ -42,6 +49,9 @@ Memory scanning parameters can be modified at run-time by writing to the ...@@ -42,6 +49,9 @@ Memory scanning parameters can be modified at run-time by writing to the
scan=<secs> - set the automatic memory scanning period in seconds scan=<secs> - set the automatic memory scanning period in seconds
(default 600, 0 to stop the automatic scanning) (default 600, 0 to stop the automatic scanning)
scan - trigger a memory scan scan - trigger a memory scan
clear - clear list of current memory leak suspects, done by
marking all current reported unreferenced objects grey
dump=<addr> - dump information about the object found at <addr>
Kmemleak can also be disabled at boot-time by passing "kmemleak=off" on Kmemleak can also be disabled at boot-time by passing "kmemleak=off" on
the kernel command line. the kernel command line.
...@@ -86,6 +96,27 @@ avoid this, kmemleak can also store the number of values pointing to an ...@@ -86,6 +96,27 @@ avoid this, kmemleak can also store the number of values pointing to an
address inside the block address range that need to be found so that the address inside the block address range that need to be found so that the
block is not considered a leak. One example is __vmalloc(). block is not considered a leak. One example is __vmalloc().
Testing specific sections with kmemleak
---------------------------------------
Upon initial bootup your /sys/kernel/debug/kmemleak output page may be
quite extensive. This can also be the case if you have very buggy code
when doing development. To work around these situations you can use the
'clear' command to clear all reported unreferenced objects from the
/sys/kernel/debug/kmemleak output. By issuing a 'scan' after a 'clear'
you can find new unreferenced objects; this should help with testing
specific sections of code.
To test a critical section on demand with a clean kmemleak do:
# echo clear > /sys/kernel/debug/kmemleak
... test your kernel or modules ...
# echo scan > /sys/kernel/debug/kmemleak
Then as usual to get your report with:
# cat /sys/kernel/debug/kmemleak
Kmemleak API Kmemleak API
------------ ------------
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/kmemleak.h>
#include <asm/e820.h> #include <asm/e820.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/iommu.h> #include <asm/iommu.h>
...@@ -94,6 +95,11 @@ static u32 __init allocate_aperture(void) ...@@ -94,6 +95,11 @@ static u32 __init allocate_aperture(void)
* code for safe * code for safe
*/ */
p = __alloc_bootmem_nopanic(aper_size, aper_size, 512ULL<<20); p = __alloc_bootmem_nopanic(aper_size, aper_size, 512ULL<<20);
/*
* Kmemleak should not scan this block as it may not be mapped via the
* kernel direct mapping.
*/
kmemleak_ignore(p);
if (!p || __pa(p)+aper_size > 0xffffffff) { if (!p || __pa(p)+aper_size > 0xffffffff) {
printk(KERN_ERR printk(KERN_ERR
"Cannot allocate aperture memory hole (%p,%uK)\n", "Cannot allocate aperture memory hole (%p,%uK)\n",
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/dmar.h> #include <linux/dmar.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/kmemleak.h>
#include <asm/proto.h> #include <asm/proto.h>
#include <asm/dma.h> #include <asm/dma.h>
...@@ -88,6 +89,11 @@ void __init dma32_reserve_bootmem(void) ...@@ -88,6 +89,11 @@ void __init dma32_reserve_bootmem(void)
size = roundup(dma32_bootmem_size, align); size = roundup(dma32_bootmem_size, align);
dma32_bootmem_ptr = __alloc_bootmem_nopanic(size, align, dma32_bootmem_ptr = __alloc_bootmem_nopanic(size, align,
512ULL<<20); 512ULL<<20);
/*
* Kmemleak should not scan this block as it may not be mapped via the
* kernel direct mapping.
*/
kmemleak_ignore(dma32_bootmem_ptr);
if (dma32_bootmem_ptr) if (dma32_bootmem_ptr)
dma32_bootmem_size = size; dma32_bootmem_size = size;
else else
......
...@@ -331,6 +331,20 @@ static void kmemcheck_read_strict(struct pt_regs *regs, ...@@ -331,6 +331,20 @@ static void kmemcheck_read_strict(struct pt_regs *regs,
kmemcheck_shadow_set(shadow, size); kmemcheck_shadow_set(shadow, size);
} }
bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size)
{
enum kmemcheck_shadow status;
void *shadow;
shadow = kmemcheck_shadow_lookup(addr);
if (!shadow)
return true;
status = kmemcheck_shadow_test(shadow, size);
return status == KMEMCHECK_SHADOW_INITIALIZED;
}
/* Access may cross page boundary */ /* Access may cross page boundary */
static void kmemcheck_read(struct pt_regs *regs, static void kmemcheck_read(struct pt_regs *regs,
unsigned long addr, unsigned int size) unsigned long addr, unsigned int size)
......
...@@ -34,6 +34,8 @@ void kmemcheck_mark_initialized_pages(struct page *p, unsigned int n); ...@@ -34,6 +34,8 @@ void kmemcheck_mark_initialized_pages(struct page *p, unsigned int n);
int kmemcheck_show_addr(unsigned long address); int kmemcheck_show_addr(unsigned long address);
int kmemcheck_hide_addr(unsigned long address); int kmemcheck_hide_addr(unsigned long address);
bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size);
#else #else
#define kmemcheck_enabled 0 #define kmemcheck_enabled 0
...@@ -99,6 +101,11 @@ static inline void kmemcheck_mark_initialized_pages(struct page *p, ...@@ -99,6 +101,11 @@ static inline void kmemcheck_mark_initialized_pages(struct page *p,
{ {
} }
static inline bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size)
{
return true;
}
#endif /* CONFIG_KMEMCHECK */ #endif /* CONFIG_KMEMCHECK */
/* /*
......
...@@ -23,18 +23,18 @@ ...@@ -23,18 +23,18 @@
#ifdef CONFIG_DEBUG_KMEMLEAK #ifdef CONFIG_DEBUG_KMEMLEAK
extern void kmemleak_init(void); extern void kmemleak_init(void) __ref;
extern void kmemleak_alloc(const void *ptr, size_t size, int min_count, extern void kmemleak_alloc(const void *ptr, size_t size, int min_count,
gfp_t gfp); gfp_t gfp) __ref;
extern void kmemleak_free(const void *ptr); extern void kmemleak_free(const void *ptr) __ref;
extern void kmemleak_free_part(const void *ptr, size_t size); extern void kmemleak_free_part(const void *ptr, size_t size) __ref;
extern void kmemleak_padding(const void *ptr, unsigned long offset, extern void kmemleak_padding(const void *ptr, unsigned long offset,
size_t size); size_t size) __ref;
extern void kmemleak_not_leak(const void *ptr); extern void kmemleak_not_leak(const void *ptr) __ref;
extern void kmemleak_ignore(const void *ptr); extern void kmemleak_ignore(const void *ptr) __ref;
extern void kmemleak_scan_area(const void *ptr, unsigned long offset, extern void kmemleak_scan_area(const void *ptr, unsigned long offset,
size_t length, gfp_t gfp); size_t length, gfp_t gfp) __ref;
extern void kmemleak_no_scan(const void *ptr); extern void kmemleak_no_scan(const void *ptr) __ref;
static inline void kmemleak_alloc_recursive(const void *ptr, size_t size, static inline void kmemleak_alloc_recursive(const void *ptr, size_t size,
int min_count, unsigned long flags, int min_count, unsigned long flags,
......
...@@ -521,7 +521,11 @@ static void * __init alloc_bootmem_core(struct bootmem_data *bdata, ...@@ -521,7 +521,11 @@ static void * __init alloc_bootmem_core(struct bootmem_data *bdata,
region = phys_to_virt(PFN_PHYS(bdata->node_min_pfn) + region = phys_to_virt(PFN_PHYS(bdata->node_min_pfn) +
start_off); start_off);
memset(region, 0, size); memset(region, 0, size);
kmemleak_alloc(region, size, 1, 0); /*
* The min_count is set to 0 so that bootmem allocated blocks
* are never reported as leaks.
*/
kmemleak_alloc(region, size, 0, 0);
return region; return region;
} }
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment