Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 177829
b: refs/heads/master
c: 04609cc
h: refs/heads/master
i:
  177827: 3b988b0
v: v3
  • Loading branch information
Catalin Marinas committed Oct 28, 2009
1 parent f7ba4a0 commit 5ca1074
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 55 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fefdd336b2a2f7617e0c8a0777c731d9ed6454ae
refs/heads/master: 04609ccc40c4e8f3eabe8894eb0de881c8b984fd
124 changes: 70 additions & 54 deletions trunk/mm/kmemleak.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
#include <linux/nodemask.h>
#include <linux/mm.h>
#include <linux/workqueue.h>
#include <linux/crc32.h>

#include <asm/sections.h>
#include <asm/processor.h>
Expand All @@ -108,7 +109,6 @@
#define MSECS_MIN_AGE 5000 /* minimum object age for reporting */
#define SECS_FIRST_SCAN 60 /* delay before the first scan */
#define SECS_SCAN_WAIT 600 /* subsequent auto scanning delay */
#define GRAY_LIST_PASSES 25 /* maximum number of gray list scans */
#define MAX_SCAN_SIZE 4096 /* maximum size of a scanned block */

#define BYTES_PER_POINTER sizeof(void *)
Expand Down Expand Up @@ -149,6 +149,8 @@ struct kmemleak_object {
int min_count;
/* the total number of pointers found pointing to this object */
int count;
/* checksum for detecting modified objects */
u32 checksum;
/* memory ranges to be scanned inside an object (empty for all) */
struct hlist_head area_list;
unsigned long trace[MAX_TRACE];
Expand All @@ -164,8 +166,6 @@ struct kmemleak_object {
#define OBJECT_REPORTED (1 << 1)
/* flag set to not scan the object */
#define OBJECT_NO_SCAN (1 << 2)
/* flag set on newly allocated objects */
#define OBJECT_NEW (1 << 3)

/* number of bytes to print per line; must be 16 or 32 */
#define HEX_ROW_SIZE 16
Expand Down Expand Up @@ -321,19 +321,14 @@ static bool color_gray(const struct kmemleak_object *object)
object->count >= object->min_count;
}

static bool color_black(const struct kmemleak_object *object)
{
return object->min_count == KMEMLEAK_BLACK;
}

/*
* Objects are considered unreferenced only if their color is white, they have
* not be deleted and have a minimum age to avoid false positives caused by
* pointers temporarily stored in CPU registers.
*/
static bool unreferenced_object(struct kmemleak_object *object)
{
return (object->flags & OBJECT_ALLOCATED) && color_white(object) &&
return (color_white(object) && object->flags & OBJECT_ALLOCATED) &&
time_before_eq(object->jiffies + jiffies_min_age,
jiffies_last_scan);
}
Expand Down Expand Up @@ -381,6 +376,7 @@ static void dump_object_info(struct kmemleak_object *object)
pr_notice(" min_count = %d\n", object->min_count);
pr_notice(" count = %d\n", object->count);
pr_notice(" flags = 0x%lx\n", object->flags);
pr_notice(" checksum = %d\n", object->checksum);
pr_notice(" backtrace:\n");
print_stack_trace(&trace, 4);
}
Expand Down Expand Up @@ -522,12 +518,13 @@ static struct kmemleak_object *create_object(unsigned long ptr, size_t size,
INIT_HLIST_HEAD(&object->area_list);
spin_lock_init(&object->lock);
atomic_set(&object->use_count, 1);
object->flags = OBJECT_ALLOCATED | OBJECT_NEW;
object->flags = OBJECT_ALLOCATED;
object->pointer = ptr;
object->size = size;
object->min_count = min_count;
object->count = -1; /* no color initially */
object->count = 0; /* white color initially */
object->jiffies = jiffies;
object->checksum = 0;

/* task information */
if (in_irq()) {
Expand Down Expand Up @@ -948,6 +945,20 @@ void __ref kmemleak_no_scan(const void *ptr)
}
EXPORT_SYMBOL(kmemleak_no_scan);

/*
* Update an object's checksum and return true if it was modified.
*/
static bool update_checksum(struct kmemleak_object *object)
{
u32 old_csum = object->checksum;

if (!kmemcheck_is_obj_initialized(object->pointer, object->size))
return false;

object->checksum = crc32(0, (void *)object->pointer, object->size);
return object->checksum != old_csum;
}

/*
* Memory scanning is a long process and it needs to be interruptable. This
* function checks whether such interrupt condition occured.
Expand Down Expand Up @@ -1081,6 +1092,39 @@ static void scan_object(struct kmemleak_object *object)
spin_unlock_irqrestore(&object->lock, flags);
}

/*
* Scan the objects already referenced (gray objects). More objects will be
* referenced and, if there are no memory leaks, all the objects are scanned.
*/
static void scan_gray_list(void)
{
struct kmemleak_object *object, *tmp;

/*
* The list traversal is safe for both tail additions and removals
* from inside the loop. The kmemleak objects cannot be freed from
* outside the loop because their use_count was incremented.
*/
object = list_entry(gray_list.next, typeof(*object), gray_list);
while (&object->gray_list != &gray_list) {
cond_resched();

/* may add new objects to the list */
if (!scan_should_stop())
scan_object(object);

tmp = list_entry(object->gray_list.next, typeof(*object),
gray_list);

/* remove the object from the list and release it */
list_del(&object->gray_list);
put_object(object);

object = tmp;
}
WARN_ON(!list_empty(&gray_list));
}

/*
* Scan data sections and all the referenced memory blocks allocated via the
* kernel's standard allocators. This function must be called with the
Expand All @@ -1089,10 +1133,9 @@ static void scan_object(struct kmemleak_object *object)
static void kmemleak_scan(void)
{
unsigned long flags;
struct kmemleak_object *object, *tmp;
struct kmemleak_object *object;
int i;
int new_leaks = 0;
int gray_list_pass = 0;

jiffies_last_scan = jiffies;

Expand All @@ -1113,7 +1156,6 @@ static void kmemleak_scan(void)
#endif
/* reset the reference count (whiten the object) */
object->count = 0;
object->flags &= ~OBJECT_NEW;
if (color_gray(object) && get_object(object))
list_add_tail(&object->gray_list, &gray_list);

Expand Down Expand Up @@ -1171,62 +1213,36 @@ static void kmemleak_scan(void)

/*
* Scan the objects already referenced from the sections scanned
* above. More objects will be referenced and, if there are no memory
* leaks, all the objects will be scanned. The list traversal is safe
* for both tail additions and removals from inside the loop. The
* kmemleak objects cannot be freed from outside the loop because their
* use_count was increased.
* above.
*/
repeat:
object = list_entry(gray_list.next, typeof(*object), gray_list);
while (&object->gray_list != &gray_list) {
cond_resched();

/* may add new objects to the list */
if (!scan_should_stop())
scan_object(object);

tmp = list_entry(object->gray_list.next, typeof(*object),
gray_list);

/* remove the object from the list and release it */
list_del(&object->gray_list);
put_object(object);

object = tmp;
}

if (scan_should_stop() || ++gray_list_pass >= GRAY_LIST_PASSES)
goto scan_end;
scan_gray_list();

/*
* Check for new objects allocated during this scanning and add them
* to the gray list.
* Check for new or unreferenced objects modified since the previous
* scan and color them gray until the next scan.
*/
rcu_read_lock();
list_for_each_entry_rcu(object, &object_list, object_list) {
spin_lock_irqsave(&object->lock, flags);
if ((object->flags & OBJECT_NEW) && !color_black(object) &&
get_object(object)) {
object->flags &= ~OBJECT_NEW;
if (color_white(object) && (object->flags & OBJECT_ALLOCATED)
&& update_checksum(object) && get_object(object)) {
/* color it gray temporarily */
object->count = object->min_count;
list_add_tail(&object->gray_list, &gray_list);
}
spin_unlock_irqrestore(&object->lock, flags);
}
rcu_read_unlock();

if (!list_empty(&gray_list))
goto repeat;

scan_end:
WARN_ON(!list_empty(&gray_list));
/*
* Re-scan the gray list for modified unreferenced objects.
*/
scan_gray_list();

/*
* If scanning was stopped or new objects were being allocated at a
* higher rate than gray list scanning, do not report any new
* unreferenced objects.
* If scanning was stopped do not report any new unreferenced objects.
*/
if (scan_should_stop() || gray_list_pass >= GRAY_LIST_PASSES)
if (scan_should_stop())
return;

/*
Expand Down

0 comments on commit 5ca1074

Please sign in to comment.