* [PATCH 00/10] Kernel memory leak detector 0.8
@ 2006-07-10 22:09 Catalin Marinas
2006-07-10 22:09 ` [PATCH 01/10] Base support for kmemleak Catalin Marinas
` (10 more replies)
0 siblings, 11 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-10 22:09 UTC (permalink / raw)
To: linux-kernel
This is a new version (0.8) of the kernel memory leak detector. See
the Documentation/kmemleak.txt file for a more detailed
description. The patches are downloadable from (the whole patch or the
broken-out series):
http://homepage.ntlworld.com/cmarinas/kmemleak/patch-2.6.18-rc1-kmemleak-0.8.bz2
http://homepage.ntlworld.com/cmarinas/kmemleak/patches-kmemleak-0.8.tar.bz2
What's new in this version:
- reviewers comments implemented
- added support for type ids (currently approximated by sizeof)
- NUMA support
- reduced the memory allocation/freeing overhead by adding the
pointer aliases to the radix tree only when scanning the memory
- improved documentation and in-code comments
To do:
- more testing
- more investigation into the task stacks scanning
- precise type identification (after first assessing the efficiency of
the current method as it requires changes to the kernel API)
- (support for ioremap tracking)
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH 01/10] Base support for kmemleak
2006-07-10 22:09 [PATCH 00/10] Kernel memory leak detector 0.8 Catalin Marinas
@ 2006-07-10 22:09 ` Catalin Marinas
2006-07-10 22:09 ` [PATCH 02/10] Some documentation " Catalin Marinas
` (9 subsequent siblings)
10 siblings, 0 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-10 22:09 UTC (permalink / raw)
To: linux-kernel
From: Catalin Marinas <catalin.marinas@arm.com>
This patch adds the base support for the kernel memory leak detector. It
traces the memory allocation/freeing in a way similar to the Boehm's
conservative garbage collector, the difference being that the orphan
pointers are not freed but only shown in /proc/memleak. Enabling this
feature would introduce an overhead to memory allocations.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
include/linux/kernel.h | 7
include/linux/memleak.h | 111 ++++
init/main.c | 3
lib/Kconfig.debug | 66 ++
mm/Makefile | 2
mm/memleak.c | 1309 +++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 1495 insertions(+), 3 deletions(-)
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 5c1ec1f..c031c18 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -13,6 +13,7 @@ #include <linux/stddef.h>
#include <linux/types.h>
#include <linux/compiler.h>
#include <linux/bitops.h>
+#include <linux/memleak.h>
#include <asm/byteorder.h>
#include <asm/bug.h>
@@ -290,9 +291,13 @@ #define max_t(type,x,y) \
* @member: the name of the member within the struct.
*
*/
-#define container_of(ptr, type, member) ({ \
+#define __container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
+#define container_of(ptr, type, member) ({ \
+ DECLARE_MEMLEAK_OFFSET(container_of, type, member); \
+ __container_of(ptr, type, member); \
+})
/*
* Check at compile time that something is of a particular type.
diff --git a/include/linux/memleak.h b/include/linux/memleak.h
new file mode 100644
index 0000000..39669bf
--- /dev/null
+++ b/include/linux/memleak.h
@@ -0,0 +1,111 @@
+/*
+ * include/linux/memleak.h
+ *
+ * Copyright (C) 2006 ARM Limited
+ * Written by Catalin Marinas <catalin.marinas@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __MEMLEAK_H
+#define __MEMLEAK_H
+
+#include <linux/stddef.h>
+
+struct memleak_offset {
+ unsigned long type_id;
+ unsigned long member_type_id;
+ unsigned long offset;
+};
+
+/* type id approximation */
+#define ml_guess_typeid(size) ((unsigned long)(size))
+#define ml_typeid(type) ml_guess_typeid(sizeof(type))
+#define ml_sizeof(typeid) ((size_t)(typeid))
+
+#ifdef CONFIG_DEBUG_MEMLEAK
+
+/* if offsetof(type, member) is not a constant known at compile time,
+ * just use 0 instead since we cannot add it to the
+ * .init.memleak_offsets section
+ */
+#define memleak_offsetof(type, member) \
+ (__builtin_constant_p(offsetof(type, member)) ? \
+ offsetof(type, member) : 0)
+
+#define DECLARE_MEMLEAK_OFFSET(name, type, member) \
+ static const struct memleak_offset \
+ __attribute__ ((__section__ (".init.memleak_offsets"))) \
+ __attribute_used__ __memleak_offset__##name = { \
+ ml_typeid(type), \
+ ml_typeid(typeof(((type *)0)->member)), \
+ memleak_offsetof(type, member) \
+ }
+
+extern void memleak_init(void);
+extern void memleak_alloc(const void *ptr, size_t size, int ref_count);
+extern void memleak_free(const void *ptr);
+extern void memleak_padding(const void *ptr, unsigned long offset, size_t size);
+extern void memleak_not_leak(const void *ptr);
+extern void memleak_ignore(const void *ptr);
+extern void memleak_scan_area(const void *ptr, unsigned long offset, size_t length);
+extern void memleak_insert_aliases(struct memleak_offset *ml_off_start,
+ struct memleak_offset *ml_off_end);
+
+static inline void memleak_erase(void **ptr)
+{
+ *ptr = NULL;
+}
+
+#define memleak_container(type, member) { \
+ DECLARE_MEMLEAK_OFFSET(container_of, type, member); \
+}
+
+extern void memleak_typeid_raw(const void *ptr, unsigned long type_id);
+#define memleak_typeid(ptr, type) \
+ memleak_typeid_raw(ptr, ml_typeid(type))
+
+#else
+
+#define DECLARE_MEMLEAK_OFFSET(name, type, member)
+
+static inline void memleak_init(void)
+{ }
+static inline void memleak_alloc(const void *ptr, size_t size, int ref_count)
+{ }
+static inline void memleak_free(const void *ptr)
+{ }
+static inline void memleak_padding(const void *ptr, unsigned long offset, size_t size)
+{ }
+static inline void memleak_not_leak(const void *ptr)
+{ }
+static inline void memleak_ignore(const void *ptr)
+{ }
+static inline void memleak_scan_area(const void *ptr, unsigned long offset, size_t length)
+{ }
+static inline void memleak_insert_aliases(struct memleak_offset *ml_off_start,
+ struct memleak_offset *ml_off_end)
+{ }
+static inline void memleak_erase(void **ptr)
+{ }
+
+#define memleak_container(type, member)
+
+static inline void memleak_typeid_raw(const void *ptr, unsigned long type_id)
+{ }
+#define memleak_typeid(ptr, type)
+
+#endif /* CONFIG_DEBUG_MEMLEAK */
+
+#endif /* __MEMLEAK_H */
diff --git a/init/main.c b/init/main.c
index 628b8e9..7db97ab 100644
--- a/init/main.c
+++ b/init/main.c
@@ -546,6 +546,8 @@ #endif
cpuset_init_early();
mem_init();
kmem_cache_init();
+ radix_tree_init();
+ memleak_init();
setup_per_cpu_pageset();
numa_policy_init();
if (late_time_init)
@@ -566,7 +568,6 @@ #endif
key_init();
security_init();
vfs_caches_init(num_physpages);
- radix_tree_init();
signals_init();
/* rootfs populating might need page-writeback */
page_writeback_init();
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index e5889b1..6c56be2 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -105,6 +105,72 @@ config DEBUG_SLAB_LEAK
bool "Memory leak debugging"
depends on DEBUG_SLAB
+menuconfig DEBUG_MEMLEAK
+ bool "Kernel memory leak detector"
+ default n
+ depends on EXPERIMENTAL && DEBUG_SLAB
+ select DEBUG_FS
+ help
+ Say Y here if you want to enable the memory leak
+ detector. The memory allocation/freeing is traced in a way
+ similar to the Boehm's conservative garbage collector, the
+ difference being that the orphan pointers are not freed but
+ only shown in /sys/kernel/debug/memleak. Enabling this
+ feature will introduce an overhead to memory
+ allocations. See Documentation/kmemleak.txt for more
+ details.
+
+ In order to access the memleak file, debugfs needs to be
+ mounted (usually at /sys/kernel/debug).
+
+config DEBUG_MEMLEAK_TRACE_LENGTH
+ int "KMemLeak stack trace length"
+ default 4
+ depends on DEBUG_MEMLEAK && FRAME_POINTER
+ help
+ This option sets the length of the stack trace for the
+ allocated pointers tracked by kmemleak.
+
+config DEBUG_MEMLEAK_PREINIT_POINTERS
+ int "KMemLeak pre-init actions buffer size"
+ default 512
+ depends on DEBUG_MEMLEAK
+ help
+ This is the buffer for storing the memory allocation/freeing
+ calls before kmemleak is fully initialized. Each element in
+ the buffer takes 24 bytes on a 32 bit architecture. This
+ buffer will be freed once the system initialization is
+ completed.
+
+config DEBUG_MEMLEAK_SECONDARY_ALIASES
+ bool "Create secondary level pointer aliases"
+ default y
+ depends on DEBUG_MEMLEAK
+ help
+ This option creates aliases for container_of(container_of(member))
+ access to pointers. Disabling this option reduces the chances of
+ false negatives but it can slightly increase the number of false
+ positives.
+
+config DEBUG_MEMLEAK_TASK_STACKS
+ bool "Scan task kernel stacks"
+ default n
+ depends on DEBUG_MEMLEAK
+ help
+ This option enables the scanning of the task kernel
+ stacks. Note that this option can introduce a lot of false
+ negatives because of the randomness of stacks content.
+
+config DEBUG_MEMLEAK_ORPHAN_FREEING
+ bool "Notify when freeing orphan pointers"
+ default n
+ depends on DEBUG_MEMLEAK
+ help
+ This option enables the notification when pointers
+ considered leaks are freed. The stack dump and the pointer
+ information displayed allow an easier identification of
+ false positives.
+
config DEBUG_PREEMPT
bool "Debug preemptible kernel"
depends on DEBUG_KERNEL && PREEMPT && TRACE_IRQFLAGS_SUPPORT
diff --git a/mm/Makefile b/mm/Makefile
index 9dd824c..edccbc0 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -23,4 +23,4 @@ obj-$(CONFIG_SLAB) += slab.o
obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
obj-$(CONFIG_FS_XIP) += filemap_xip.o
obj-$(CONFIG_MIGRATION) += migrate.o
-
+obj-$(CONFIG_DEBUG_MEMLEAK) += memleak.o
diff --git a/mm/memleak.c b/mm/memleak.c
new file mode 100644
index 0000000..4569f91
--- /dev/null
+++ b/mm/memleak.c
@@ -0,0 +1,1309 @@
+/*
+ * mm/memleak.c
+ *
+ * Copyright (C) 2006 ARM Limited
+ * Written by Catalin Marinas <catalin.marinas@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* #define DEBUG */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/radix-tree.h>
+#include <linux/gfp.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kallsyms.h>
+#include <linux/mman.h>
+#include <linux/nodemask.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
+#include <linux/mutex.h>
+#include <linux/cpumask.h>
+
+#include <asm/bitops.h>
+#include <asm/sections.h>
+#include <asm/percpu.h>
+#include <asm/processor.h>
+#include <asm/thread_info.h>
+#include <asm/atomic.h>
+
+#include <linux/memleak.h>
+
+#ifdef CONFIG_FRAME_POINTER
+#define MAX_TRACE CONFIG_DEBUG_MEMLEAK_TRACE_LENGTH
+#else
+#define MAX_TRACE 1
+#endif
+
+#define SCAN_BLOCK_SIZE 4096 /* maximum scan length with interrupts disabled */
+#define PREINIT_POINTERS CONFIG_DEBUG_MEMLEAK_PREINIT_POINTERS
+#define BYTES_PER_WORD sizeof(void *)
+
+extern struct memleak_offset __memleak_offsets_start[];
+extern struct memleak_offset __memleak_offsets_end[];
+
+struct memleak_alias {
+ struct hlist_node node;
+ unsigned long offset;
+};
+
+struct memleak_scan_area {
+ struct hlist_node node;
+ unsigned long offset;
+ size_t length;
+};
+
+struct memleak_pointer {
+ unsigned long flags;
+ struct list_head pointer_list;
+ struct list_head gray_list;
+ int use_count;
+ unsigned long pointer;
+ unsigned long offset; /* padding */
+ size_t size;
+ unsigned long type_id;
+ int ref_count; /* the minimum encounters of the value */
+ int count; /* the ecounters of the value */
+ struct hlist_head *alias_list;
+ struct hlist_head area_list; /* areas to be scanned (or empty for all) */
+ unsigned long trace[MAX_TRACE];
+};
+
+enum memleak_action {
+ MEMLEAK_ALLOC,
+ MEMLEAK_FREE,
+ MEMLEAK_PADDING,
+ MEMLEAK_NOT_LEAK,
+ MEMLEAK_IGNORE,
+ MEMLEAK_SCAN_AREA,
+ MEMLEAK_TYPEID
+};
+
+struct memleak_preinit_pointer {
+ enum memleak_action type;
+ const void *pointer;
+ unsigned long offset;
+ size_t size;
+ unsigned long type_id;
+ int ref_count;
+};
+
+/* Pointer colors, encoded with count and ref_count:
+ * - white - orphan block, i.e. not enough references to it (ref_count >= 1)
+ * - gray - referred at least once and therefore non-orphan (ref_count == 0)
+ * - black - ignore; it doesn't contain references (text section) (ref_count == -1)
+ */
+static inline int color_white(const struct memleak_pointer *pointer)
+{
+ return pointer->count != -1 && pointer->count < pointer->ref_count;
+}
+
+static inline int color_gray(const struct memleak_pointer *pointer)
+{
+ return pointer->ref_count != -1 && pointer->count >= pointer->ref_count;
+}
+
+static inline int color_black(const struct memleak_pointer *pointer)
+{
+ return pointer->ref_count == -1;
+}
+
+/* Tree storing the pointer aliases indexed by size */
+static RADIX_TREE(alias_tree, GFP_ATOMIC);
+/* Tree storing all the possible pointers, indexed by the pointer value */
+static RADIX_TREE(pointer_tree, GFP_ATOMIC);
+/* The list of all allocated pointers */
+static LIST_HEAD(pointer_list);
+/* The list of the gray pointers */
+static LIST_HEAD(gray_list);
+
+static struct kmem_cache *pointer_cache;
+/* Used to avoid recursive call via the kmalloc/kfree functions */
+static spinlock_t memleak_lock = SPIN_LOCK_UNLOCKED;
+static cpumask_t memleak_cpu_mask = CPU_MASK_NONE;
+static DEFINE_MUTEX(memleak_mutex);
+static atomic_t memleak_initialized = ATOMIC_INIT(0);
+static int __initdata preinit_pos;
+static struct memleak_preinit_pointer __initdata preinit_pointers[PREINIT_POINTERS];
+/* last allocated pointer (optimization); protected by memleak_lock */
+static struct memleak_pointer *last_pointer;
+
+/* pointer flags */
+#define POINTER_ALLOCATED 1
+#define POINTER_ALIASES 2
+
+#ifdef CONFIG_KALLSYMS
+static inline void dump_symbol_name(unsigned long addr)
+{
+ char namebuf[KSYM_NAME_LEN + 1] = "";
+ char *modname;
+ unsigned long symsize;
+ unsigned long offset = 0;
+
+ kallsyms_lookup(addr, &symsize, &offset, &modname, namebuf);
+ printk(KERN_NOTICE " %lx: <%s>\n", addr, namebuf);
+}
+#else
+static inline void dump_symbol_name(unsigned long addr)
+{
+ printk(KERN_NOTICE " %lx\n", addr);
+}
+#endif
+
+#ifdef DEBUG
+static inline void dump_pointer_internals(struct memleak_pointer *pointer)
+{
+ struct memleak_alias *alias;
+ struct hlist_node *elem;
+
+ printk(KERN_NOTICE " size = %d\n", pointer->size);
+ printk(KERN_NOTICE " ref_count = %d\n", pointer->ref_count);
+ printk(KERN_NOTICE " count = %d\n", pointer->count);
+ printk(KERN_NOTICE " aliases:\n");
+ if (pointer->alias_list)
+ hlist_for_each_entry(alias, elem, pointer->alias_list, node)
+ printk(KERN_NOTICE " 0x%lx\n", alias->offset);
+}
+#else
+static inline void dump_pointer_internals(struct memleak_pointer *pointer)
+{ }
+#endif
+
+static void dump_pointer_info(struct memleak_pointer *pointer)
+{
+ int i;
+
+ printk(KERN_NOTICE "kmemleak: pointer 0x%08lx:\n", pointer->pointer);
+ dump_pointer_internals(pointer);
+ printk(KERN_NOTICE " trace:\n");
+ for (i = 0; i < MAX_TRACE; i++) {
+ unsigned long trace = pointer->trace[i];
+
+ if (!trace)
+ break;
+ dump_symbol_name(trace);
+ }
+}
+
+/* Insert an element into the aliases radix tree.
+ * Return 0 on success.
+ */
+static int insert_alias(unsigned long type_id, unsigned long offset)
+{
+ int ret = 0;
+ struct hlist_head *alias_list;
+ struct memleak_alias *alias;
+
+ if (type_id == 0 || offset == 0 || offset >= ml_sizeof(type_id)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ offset &= ~(BYTES_PER_WORD - 1);
+
+ alias_list = radix_tree_lookup(&alias_tree, type_id);
+ if (alias_list) {
+ struct hlist_node *elem;
+
+ hlist_for_each_entry(alias, elem, alias_list, node) {
+ if (alias->offset == offset) {
+ ret = -EEXIST;
+ goto out;
+ }
+ }
+ } else {
+ alias_list = kmalloc(sizeof(*alias_list), GFP_ATOMIC);
+ if (!alias_list)
+ panic("kmemleak: cannot allocate initial memory\n");
+ INIT_HLIST_HEAD(alias_list);
+
+ ret = radix_tree_insert(&alias_tree, type_id, alias_list);
+ if (ret)
+ panic("kmemleak: cannot insert into the aliases radix tree: %d\n", ret);
+ }
+
+ alias = kmalloc(sizeof(*alias), GFP_ATOMIC);
+ if (!alias)
+ panic("kmemleak: cannot allocate initial memory\n");
+ INIT_HLIST_NODE(&alias->node);
+ alias->offset = offset;
+
+ hlist_add_head(&alias->node, alias_list);
+
+ out:
+ return ret;
+}
+
+/* Insert pointer aliases the from the given array */
+void memleak_insert_aliases(struct memleak_offset *ml_off_start,
+ struct memleak_offset *ml_off_end)
+{
+ struct memleak_offset *ml_off;
+ int i = 0;
+ unsigned long flags;
+ unsigned int cpu_id;
+
+ pr_debug("%s(0x%p, 0x%p)\n", __FUNCTION__, ml_off_start, ml_off_end);
+
+ spin_lock_irqsave(&memleak_lock, flags);
+
+ /* do not track the kmemleak allocated pointers */
+ cpu_id = smp_processor_id();
+ if (cpu_test_and_set(cpu_id, memleak_cpu_mask))
+ BUG();
+
+ /* primary aliases - container_of(member) */
+ for (ml_off = ml_off_start; ml_off < ml_off_end; ml_off++)
+ if (!insert_alias(ml_off->type_id, ml_off->offset))
+ i++;
+ pr_debug("kmemleak: found %d primary alias(es)\n", i);
+
+#ifdef CONFIG_DEBUG_MEMLEAK_SECONDARY_ALIASES
+ /* secondary aliases - container_of(container_of(member)) */
+ for (ml_off = ml_off_start; ml_off < ml_off_end; ml_off++) {
+ struct hlist_head *alias_list;
+ struct memleak_alias *alias;
+ struct hlist_node *elem;
+
+ alias_list = radix_tree_lookup(&alias_tree, ml_off->member_type_id);
+ if (!alias_list)
+ continue;
+
+ hlist_for_each_entry(alias, elem, alias_list, node)
+ if (!insert_alias(ml_off->type_id, ml_off->offset + alias->offset))
+ i++;
+ }
+ pr_debug("kmemleak: found %d alias(es)\n", i);
+#endif
+
+ cpu_clear(cpu_id, memleak_cpu_mask);
+ spin_unlock_irqrestore(&memleak_lock, flags);
+}
+EXPORT_SYMBOL_GPL(memleak_insert_aliases);
+
+static inline struct memleak_pointer *get_cached_pointer(unsigned long ptr)
+{
+ if (!last_pointer || ptr != last_pointer->pointer)
+ last_pointer = radix_tree_lookup(&pointer_tree, ptr);
+ return last_pointer;
+}
+
+static void create_pointer_aliases(struct memleak_pointer *pointer)
+{
+ struct memleak_alias *alias;
+ struct hlist_node *elem;
+ unsigned long ptr = pointer->pointer;
+ int err;
+
+ BUG_ON(pointer->flags & POINTER_ALIASES);
+
+ if (pointer->offset) {
+ err = radix_tree_insert(&pointer_tree, ptr + pointer->offset, pointer);
+ if (err) {
+ dump_stack();
+ panic("kmemleak: cannot insert offset into the pointer radix tree: %d\n", err);
+ }
+ }
+
+ pointer->alias_list = radix_tree_lookup(&alias_tree, pointer->type_id);
+ if (pointer->alias_list) {
+ hlist_for_each_entry(alias, elem, pointer->alias_list, node) {
+ err = radix_tree_insert(&pointer_tree, ptr
+ + pointer->offset + alias->offset,
+ pointer);
+ if (err) {
+ dump_stack();
+ panic("kmemleak: cannot insert alias into the pointer radix tree: %d\n", err);
+ }
+ }
+ }
+
+ pointer->flags |= POINTER_ALIASES;
+}
+
+static void delete_pointer_aliases(struct memleak_pointer *pointer)
+{
+ struct memleak_alias *alias;
+ struct hlist_node *elem;
+ unsigned long ptr = pointer->pointer;
+
+ BUG_ON(!(pointer->flags & POINTER_ALIASES));
+
+ if (pointer->offset)
+ radix_tree_delete(&pointer_tree, ptr + pointer->offset);
+
+ if (pointer->alias_list) {
+ hlist_for_each_entry(alias, elem, pointer->alias_list, node)
+ radix_tree_delete(&pointer_tree,
+ ptr + pointer->offset + alias->offset);
+ pointer->alias_list = NULL;
+ }
+
+ pointer->flags &= ~POINTER_ALIASES;
+}
+
+/* no need for atomic operations since memleak_lock is held anyway */
+static inline void get_pointer(struct memleak_pointer *pointer)
+{
+ pointer->use_count++;
+}
+
+/* called with memleak_lock held for pointer_list modification and
+ * memleak_cpu_mask set to avoid entering memleak_free (and deadlock)
+ */
+static void __put_pointer(struct memleak_pointer *pointer)
+{
+ struct hlist_node *elem, *tmp;
+ struct memleak_scan_area *area;
+
+ if (--pointer->use_count > 0)
+ return;
+
+ /* free the scanning areas */
+ hlist_for_each_entry_safe(area, elem, tmp, &pointer->area_list, node) {
+ hlist_del(elem);
+ kfree(area);
+ }
+
+ list_del(&pointer->pointer_list);
+ kmem_cache_free(pointer_cache, pointer);
+}
+
+static void put_pointer(struct memleak_pointer *pointer)
+{
+ unsigned long flags;
+ unsigned int cpu_id;
+
+ spin_lock_irqsave(&memleak_lock, flags);
+ cpu_id = smp_processor_id();
+ if (cpu_test_and_set(cpu_id, memleak_cpu_mask))
+ BUG();
+
+ __put_pointer(pointer);
+
+ cpu_clear(cpu_id, memleak_cpu_mask);
+ spin_unlock_irqrestore(&memleak_lock, flags);
+}
+
+/* Insert a pointer and its aliases into the pointer radix tree */
+static inline void create_pointer(unsigned long ptr, size_t size, int ref_count)
+{
+ struct memleak_pointer *pointer;
+ int err;
+#ifdef CONFIG_FRAME_POINTER
+ int i;
+ void *frame;
+#endif
+
+ pointer = kmem_cache_alloc(pointer_cache, SLAB_ATOMIC);
+ if (!pointer)
+ panic("kmemleak: cannot allocate a memleak_pointer structure\n");
+
+ last_pointer = pointer;
+
+ INIT_LIST_HEAD(&pointer->pointer_list);
+ INIT_LIST_HEAD(&pointer->gray_list);
+ INIT_HLIST_HEAD(&pointer->area_list);
+ pointer->flags = POINTER_ALLOCATED;
+ pointer->use_count = 0;
+ pointer->pointer = ptr;
+ pointer->offset = 0;
+ pointer->size = size;
+ pointer->type_id = ml_guess_typeid(size); /* type id approximation */
+ pointer->ref_count = ref_count;
+ pointer->count = -1;
+ pointer->alias_list = NULL;
+
+#ifdef CONFIG_FRAME_POINTER
+ frame = __builtin_frame_address(0);
+ for (i = 0; i < MAX_TRACE; i++) {
+ void *stack = task_stack_page(current);
+
+ if (frame < stack || frame > stack + THREAD_SIZE - BYTES_PER_WORD) {
+ pointer->trace[i] = 0;
+ continue;
+ }
+
+ pointer->trace[i] = arch_call_address(frame);
+ frame = arch_prev_frame(frame);
+ /* we don't need the return to do_exit() */
+ if (kstack_end(frame))
+ pointer->trace[i] = 0;
+ }
+#else
+ pointer->trace[0] = (unsigned long)__builtin_return_address(0);
+#endif
+
+ err = radix_tree_insert(&pointer_tree, ptr, pointer);
+ if (err) {
+ dump_stack();
+ if (err == -EEXIST) {
+ printk(KERN_NOTICE "Existing pointer:\n");
+ pointer = radix_tree_lookup(&pointer_tree, ptr);
+ dump_pointer_info(pointer);
+ }
+ panic("kmemleak: cannot insert 0x%lx into the pointer radix tree: %d\n",
+ ptr, err);
+ }
+
+ list_add_tail(&pointer->pointer_list, &pointer_list);
+ get_pointer(pointer);
+}
+
+/* Remove a pointer and its aliases from the pointer radix tree */
+static inline void delete_pointer(unsigned long ptr)
+{
+ struct memleak_pointer *pointer;
+
+ pointer = radix_tree_delete(&pointer_tree, ptr);
+ if (!pointer) {
+ dump_stack();
+ printk(KERN_WARNING "kmemleak: freeing unknown pointer value 0x%08lx\n", ptr);
+ return;
+ }
+ if (pointer->pointer != ptr) {
+ dump_stack();
+ dump_pointer_info(pointer);
+ panic("kmemleak: freeing pointer by alias 0x%08lx\n", ptr);
+ }
+
+ BUG_ON(!(pointer->flags & POINTER_ALLOCATED));
+
+ if (last_pointer && ptr == last_pointer->pointer)
+ last_pointer = NULL;
+
+#ifdef CONFIG_DEBUG_MEMLEAK_ORPHAN_FREEING
+ if (color_white(pointer)) {
+ dump_stack();
+ dump_pointer_info(pointer);
+ printk(KERN_WARNING "kmemleak: freeing orphan pointer 0x%08lx\n", ptr);
+ }
+#endif
+
+ if (pointer->flags & POINTER_ALIASES)
+ delete_pointer_aliases(pointer);
+ pointer->flags &= ~POINTER_ALLOCATED;
+ pointer->pointer = 0;
+ __put_pointer(pointer);
+}
+
+/* Re-create the pointer aliases according to the new size/offset
+ * information */
+static inline void unpad_pointer(unsigned long ptr, unsigned long offset,
+ size_t size)
+{
+ struct memleak_pointer *pointer;
+
+ pointer = get_cached_pointer(ptr);
+ if (!pointer) {
+ dump_stack();
+ panic("kmemleak: resizing unknown pointer value 0x%08lx\n", ptr);
+ }
+ if (pointer->pointer != ptr) {
+ dump_stack();
+ dump_pointer_info(pointer);
+ panic("kmemleak: resizing pointer by alias 0x%08lx\n", ptr);
+ }
+ if (offset + size > pointer->size) {
+ dump_stack();
+ dump_pointer_info(pointer);
+ panic("kmemleak: new boundaries exceed block 0x%08lx\n", ptr);
+ }
+
+ if (offset == pointer->offset && size == pointer->size)
+ return;
+
+ if (pointer->flags & POINTER_ALIASES)
+ delete_pointer_aliases(pointer);
+
+ pointer->offset = offset;
+ pointer->size = size;
+}
+
+/* Make a pointer permanently gray (false positive) */
+static inline void make_gray_pointer(unsigned long ptr)
+{
+ struct memleak_pointer *pointer;
+
+ pointer = get_cached_pointer(ptr);
+ if (!pointer) {
+ dump_stack();
+ panic("kmemleak: graying unknown pointer value 0x%08lx\n", ptr);
+ }
+ if (pointer->pointer != ptr) {
+ dump_stack();
+ dump_pointer_info(pointer);
+ panic("kmemleak: graying pointer by alias 0x%08lx\n", ptr);
+ }
+
+ pointer->ref_count = 0;
+}
+
+/* Mark the pointer as black */
+static inline void make_black_pointer(unsigned long ptr)
+{
+ struct memleak_pointer *pointer;
+
+ pointer = get_cached_pointer(ptr);
+ if (!pointer) {
+ dump_stack();
+ panic("kmemleak: blacking unknown pointer value 0x%08lx\n", ptr);
+ }
+ if (pointer->pointer != ptr) {
+ dump_stack();
+ dump_pointer_info(pointer);
+ panic("kmemleak: blacking pointer by alias 0x%08lx\n", ptr);
+ }
+
+ pointer->ref_count = -1;
+}
+
+/* Add a scanning area to the pointer */
+static inline void add_scan_area(unsigned long ptr, unsigned long offset, size_t length)
+{
+ struct memleak_pointer *pointer;
+ struct memleak_scan_area *area;
+
+ pointer = get_cached_pointer(ptr);
+ if (!pointer) {
+ dump_stack();
+ panic("kmemleak: adding scan area to unknown pointer value 0x%08lx\n", ptr);
+ }
+ if (pointer->pointer != ptr) {
+ dump_stack();
+ dump_pointer_info(pointer);
+ panic("kmemleak: adding scan area to pointer by alias 0x%08lx\n", ptr);
+ }
+ if (offset + length > pointer->size) {
+ dump_stack();
+ dump_pointer_info(pointer);
+ panic("kmemleak: scan area larger than block 0x%08lx\n", ptr);
+ }
+
+ area = kmalloc(sizeof(*area), GFP_ATOMIC);
+ if (!area)
+ panic("kmemleak: cannot allocate a scan area\n");
+
+ INIT_HLIST_NODE(&area->node);
+ area->offset = offset;
+ area->length = length;
+
+ hlist_add_head(&area->node, &pointer->area_list);
+}
+
+/* Re-create the pointer aliases according to the new type id */
+static inline void change_type_id(unsigned long ptr, unsigned long type_id)
+{
+ struct memleak_pointer *pointer;
+
+ pointer = get_cached_pointer(ptr);
+ if (!pointer) {
+ dump_stack();
+ panic("kmemleak: changing type of unknown pointer value 0x%08lx\n", ptr);
+ }
+ if (pointer->pointer != ptr) {
+ dump_stack();
+ dump_pointer_info(pointer);
+ panic("kmemleak: changing type of pointer by alias 0x%08lx\n", ptr);
+ }
+ if (ml_sizeof(type_id) > pointer->size) {
+ dump_stack();
+ dump_pointer_info(pointer);
+ panic("kmemleak: new type larger than block 0x%08lx\n", ptr);
+ }
+
+ if (!type_id || type_id == pointer->type_id)
+ return;
+
+ if (pointer->flags & POINTER_ALIASES)
+ delete_pointer_aliases(pointer);
+
+ pointer->type_id = type_id;
+}
+
+/* Allocation function hook */
+void memleak_alloc(const void *ptr, size_t size, int ref_count)
+{
+ unsigned long flags;
+ unsigned int cpu_id;
+
+ if (!ptr)
+ return;
+
+ local_irq_save(flags);
+ cpu_id = get_cpu();
+
+ /* avoid recursive calls. After disabling the interrupts, the
+ * only calls to this function on the same CPU should be from
+ * kmemleak itself and we ignore them. Calls from other CPU's
+ * would wait on the spin_lock.
+ */
+ if (cpu_test_and_set(cpu_id, memleak_cpu_mask))
+ goto out;
+
+ pr_debug("%s(0x%p, %d, %d)\n", __FUNCTION__, ptr, size, ref_count);
+
+ if (!atomic_read(&memleak_initialized)) {
+ /* no need for SMP locking since this block is
+ * executed before the other CPUs are started */
+ struct memleak_preinit_pointer *pointer;
+
+ BUG_ON(cpu_id != 0);
+
+ if (preinit_pos >= PREINIT_POINTERS)
+ panic("kmemleak: preinit pointers buffer overflow\n");
+ pointer = &preinit_pointers[preinit_pos++];
+
+ pointer->type = MEMLEAK_ALLOC;
+ pointer->pointer = ptr;
+ pointer->size = size;
+ pointer->ref_count = ref_count;
+
+ goto unmask;
+ }
+
+ spin_lock(&memleak_lock);
+ create_pointer((unsigned long)ptr, size, ref_count);
+ spin_unlock(&memleak_lock);
+
+ unmask:
+ cpu_clear(cpu_id, memleak_cpu_mask);
+ out:
+ put_cpu_no_resched();
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(memleak_alloc);
+
+/* Freeing function hook */
+void memleak_free(const void *ptr)
+{
+ unsigned long flags;
+ unsigned int cpu_id;
+
+ if (!ptr)
+ return;
+
+ local_irq_save(flags);
+ cpu_id = get_cpu();
+
+ /* avoid recursive calls. See memleak_alloc() for an explanation */
+ if (cpu_test_and_set(cpu_id, memleak_cpu_mask))
+ goto out;
+
+ pr_debug("%s(0x%p)\n", __FUNCTION__, ptr);
+
+ if (!atomic_read(&memleak_initialized)) {
+ struct memleak_preinit_pointer *pointer;
+
+ BUG_ON(cpu_id != 0);
+
+ if (preinit_pos >= PREINIT_POINTERS)
+ panic("kmemleak: preinit pointers buffer overflow\n");
+ pointer = &preinit_pointers[preinit_pos++];
+
+ pointer->type = MEMLEAK_FREE;
+ pointer->pointer = ptr;
+
+ goto unmask;
+ }
+
+ spin_lock(&memleak_lock);
+ delete_pointer((unsigned long)ptr);
+ spin_unlock(&memleak_lock);
+
+ unmask:
+ cpu_clear(cpu_id, memleak_cpu_mask);
+ out:
+ put_cpu_no_resched();
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(memleak_free);
+
+/* Change the size and location information of an allocated memory
+ * block (this is needed for allocations padding the object) */
+void memleak_padding(const void *ptr, unsigned long offset, size_t size)
+{
+ unsigned long flags;
+ unsigned int cpu_id;
+
+ if (!ptr)
+ return;
+
+ local_irq_save(flags);
+ cpu_id = get_cpu();
+
+ /* avoid recursive calls. See memleak_alloc() for an explanation */
+ if (cpu_test_and_set(cpu_id, memleak_cpu_mask))
+ goto out;
+
+ pr_debug("%s(0x%p, %d)\n", __FUNCTION__, ptr, size);
+
+ if (!atomic_read(&memleak_initialized)) {
+ struct memleak_preinit_pointer *pointer;
+
+ BUG_ON(cpu_id != 0);
+
+ if (preinit_pos >= PREINIT_POINTERS)
+ panic("kmemleak: preinit pointers buffer overflow\n");
+ pointer = &preinit_pointers[preinit_pos++];
+
+ pointer->type = MEMLEAK_PADDING;
+ pointer->pointer = ptr;
+ pointer->offset = offset;
+ pointer->size = size;
+
+ goto unmask;
+ }
+
+ spin_lock(&memleak_lock);
+ unpad_pointer((unsigned long)ptr, offset, size);
+ spin_unlock(&memleak_lock);
+
+ unmask:
+ cpu_clear(cpu_id, memleak_cpu_mask);
+ out:
+ put_cpu_no_resched();
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(memleak_padding);
+
+/* Mark a pointer as a false positive */
+void memleak_not_leak(const void *ptr)
+{
+ unsigned long flags;
+ unsigned int cpu_id;
+
+ if (!ptr)
+ return;
+
+ local_irq_save(flags);
+ cpu_id = get_cpu();
+
+ /* avoid recursive calls. See memleak_alloc() for an explanation */
+ if (cpu_test_and_set(cpu_id, memleak_cpu_mask))
+ goto out;
+
+ pr_debug("%s(0x%p)\n", __FUNCTION__, ptr);
+
+ if (!atomic_read(&memleak_initialized)) {
+ struct memleak_preinit_pointer *pointer;
+
+ BUG_ON(cpu_id != 0);
+
+ if (preinit_pos >= PREINIT_POINTERS)
+ panic("kmemleak: preinit pointers buffer overflow\n");
+ pointer = &preinit_pointers[preinit_pos++];
+
+ pointer->type = MEMLEAK_NOT_LEAK;
+ pointer->pointer = ptr;
+
+ goto unmask;
+ }
+
+ spin_lock(&memleak_lock);
+ make_gray_pointer((unsigned long)ptr);
+ spin_unlock(&memleak_lock);
+
+ unmask:
+ cpu_clear(cpu_id, memleak_cpu_mask);
+ out:
+ put_cpu_no_resched();
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(memleak_not_leak);
+
+/* Ignore this memory block */
+void memleak_ignore(const void *ptr)
+{
+ unsigned long flags;
+ unsigned int cpu_id;
+
+ if (!ptr)
+ return;
+
+ local_irq_save(flags);
+ cpu_id = get_cpu();
+
+ /* avoid recursive calls. See memleak_alloc() for an explanation */
+ if (cpu_test_and_set(cpu_id, memleak_cpu_mask))
+ goto out;
+
+ pr_debug("%s(0x%p)\n", __FUNCTION__, ptr);
+
+ if (!atomic_read(&memleak_initialized)) {
+ struct memleak_preinit_pointer *pointer;
+
+ BUG_ON(cpu_id != 0);
+
+ if (preinit_pos >= PREINIT_POINTERS)
+ panic("kmemleak: preinit pointers buffer overflow\n");
+ pointer = &preinit_pointers[preinit_pos++];
+
+ pointer->type = MEMLEAK_IGNORE;
+ pointer->pointer = ptr;
+
+ goto unmask;
+ }
+
+ spin_lock(&memleak_lock);
+ make_black_pointer((unsigned long)ptr);
+ spin_unlock(&memleak_lock);
+
+ unmask:
+ cpu_clear(cpu_id, memleak_cpu_mask);
+ out:
+ put_cpu_no_resched();
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(memleak_ignore);
+
+/* Add a scanning area to a pointer */
+void memleak_scan_area(const void *ptr, unsigned long offset, size_t length)
+{
+ unsigned long flags;
+ unsigned int cpu_id;
+
+ if (!ptr)
+ return;
+
+ local_irq_save(flags);
+ cpu_id = get_cpu();
+
+ /* avoid recursive calls. See memleak_alloc() for an explanation */
+ if (cpu_test_and_set(cpu_id, memleak_cpu_mask))
+ goto out;
+
+ pr_debug("%s(0x%p)\n", __FUNCTION__, ptr);
+
+ if (!atomic_read(&memleak_initialized)) {
+ struct memleak_preinit_pointer *pointer;
+
+ BUG_ON(cpu_id != 0);
+
+ if (preinit_pos >= PREINIT_POINTERS)
+ panic("kmemleak: preinit pointers buffer overflow\n");
+ pointer = &preinit_pointers[preinit_pos++];
+
+ pointer->type = MEMLEAK_SCAN_AREA;
+ pointer->pointer = ptr;
+ pointer->offset = offset;
+ pointer->size = length;
+
+ goto unmask;
+ }
+
+ spin_lock(&memleak_lock);
+ add_scan_area((unsigned long)ptr, offset, length);
+ spin_unlock(&memleak_lock);
+
+ unmask:
+ cpu_clear(cpu_id, memleak_cpu_mask);
+ out:
+ put_cpu_no_resched();
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(memleak_scan_area);
+
+/* Change the type id of an allocated memory block */
+void memleak_typeid_raw(const void *ptr, unsigned long type_id)
+{
+ unsigned long flags;
+ unsigned int cpu_id;
+
+ if (!ptr)
+ return;
+
+ local_irq_save(flags);
+ cpu_id = get_cpu();
+
+ /* avoid recursive calls. See memleak_alloc() for an explanation */
+ if (cpu_test_and_set(cpu_id, memleak_cpu_mask))
+ goto out;
+
+ pr_debug("%s(0x%p, %ld)\n", __FUNCTION__, ptr, type_id);
+
+ if (!atomic_read(&memleak_initialized)) {
+ struct memleak_preinit_pointer *pointer;
+
+ BUG_ON(cpu_id != 0);
+
+ if (preinit_pos >= PREINIT_POINTERS)
+ panic("kmemleak: preinit pointers buffer overflow\n");
+ pointer = &preinit_pointers[preinit_pos++];
+
+ pointer->type = MEMLEAK_TYPEID;
+ pointer->pointer = ptr;
+ pointer->type_id = type_id;
+
+ goto unmask;
+ }
+
+ spin_lock(&memleak_lock);
+ change_type_id((unsigned long)ptr, type_id);
+ spin_unlock(&memleak_lock);
+
+ unmask:
+ cpu_clear(cpu_id, memleak_cpu_mask);
+ out:
+ put_cpu_no_resched();
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(memleak_typeid_raw);
+
+/* Scan a block of memory (exclusive range) for pointers and move
+ * those found to the gray list. This function is called with
+ * memleak_lock held
+ */
+static void __scan_block(void *_start, void *_end)
+{
+ unsigned long *ptr;
+ unsigned long *start = (unsigned long *)ALIGN((unsigned long)_start,
+ BYTES_PER_WORD);
+ unsigned long *end = _end;
+
+ for (ptr = start; ptr < end; ptr++) {
+ struct memleak_pointer *pointer =
+ radix_tree_lookup(&pointer_tree,
+ (*ptr) & ~(BYTES_PER_WORD - 1));
+ if (!pointer)
+ continue;
+ if (!color_white(pointer))
+ continue;
+
+ pointer->count++;
+ /* this can happen during the grey_list traversal */
+ if (color_gray(pointer)) {
+ get_pointer(pointer);
+ list_add_tail_rcu(&pointer->gray_list, &gray_list);
+ }
+ }
+}
+
+static void scan_block(void *start, void *end)
+{
+ unsigned long flags;
+ void *s, *e;
+
+ s = start;
+ while (s < end) {
+ e = s + SCAN_BLOCK_SIZE;
+
+ spin_lock_irqsave(&memleak_lock, flags);
+ __scan_block(s, e < end ? e : end);
+ spin_unlock_irqrestore(&memleak_lock, flags);
+
+ s = e;
+ }
+}
+
+/* Scan a memory block represented by a memleak_pointer */
+static inline void scan_pointer(struct memleak_pointer *pointer)
+{
+ struct memleak_scan_area *area;
+ struct hlist_node *elem;
+ unsigned long flags;
+
+ spin_lock_irqsave(&memleak_lock, flags);
+
+ /* freed pointer */
+ if (!pointer->pointer)
+ goto out;
+
+ if (hlist_empty(&pointer->area_list))
+ __scan_block((void *)pointer->pointer,
+ (void *)(pointer->pointer + pointer->size));
+ else
+ hlist_for_each_entry(area, elem, &pointer->area_list, node) {
+ unsigned long ptr = pointer->pointer + area->offset;
+
+ __scan_block((void *)ptr, (void *)(ptr + area->length));
+ }
+
+ out:
+ spin_unlock_irqrestore(&memleak_lock, flags);
+}
+
+/* Scan the memory and print the orphan pointers */
+static void memleak_scan(void)
+{
+ unsigned long flags;
+ struct memleak_pointer *pointer, *tmp;
+#ifdef CONFIG_DEBUG_MEMLEAK_TASK_STACKS
+ struct task_struct *task;
+#endif
+ int i;
+ unsigned int cpu_id;
+
+ /* initialize pointers (make them white) and build the initial
+ * gray list. Note that create_pointer_aliases might allocate
+ * memory */
+ spin_lock_irqsave(&memleak_lock, flags);
+ cpu_id = smp_processor_id();
+ if (cpu_test_and_set(cpu_id, memleak_cpu_mask))
+ BUG();
+
+ list_for_each_entry(pointer, &pointer_list, pointer_list) {
+ /* lazy insertion of the pointer aliases into the radix tree */
+ if ((pointer->flags & POINTER_ALLOCATED)
+ && !(pointer->flags & POINTER_ALIASES))
+ create_pointer_aliases(pointer);
+
+ pointer->count = 0;
+ if (color_gray(pointer)) {
+ get_pointer(pointer);
+ list_add_tail(&pointer->gray_list, &gray_list);
+ }
+ }
+
+ cpu_clear(cpu_id, memleak_cpu_mask);
+ spin_unlock_irqrestore(&memleak_lock, flags);
+
+ /* data/bss scanning */
+ scan_block(_sdata, _edata);
+ scan_block(__bss_start, __bss_stop);
+
+#ifdef CONFIG_SMP
+ /* per-cpu scanning */
+ for (i = 0; i < NR_CPUS; i++)
+ scan_block(__per_cpu_offset[i] + __per_cpu_start,
+ __per_cpu_offset[i] + __per_cpu_end);
+#endif
+
+ /* mem_map scanning */
+ for_each_online_node(i) {
+ struct page *page, *end;
+
+ page = NODE_MEM_MAP(i);
+ end = page + NODE_DATA(i)->node_spanned_pages;
+
+ scan_block(page, end);
+ }
+
+#ifdef CONFIG_DEBUG_MEMLEAK_TASK_STACKS
+ read_lock(&tasklist_lock);
+ for_each_process(task)
+ scan_block(task_stack_page(task),
+ task_stack_page(task) + THREAD_SIZE);
+ read_unlock(&tasklist_lock);
+#endif
+
+ /* gray_list scanning. RCU is needed because new elements can
+ * be added to the list during scanning */
+ rcu_read_lock();
+ list_for_each_entry_rcu(pointer, &gray_list, gray_list)
+ scan_pointer(pointer);
+ rcu_read_unlock();
+
+ /* empty the gray list. It needs the "safe" version because
+ * put_pointer() can free the structure */
+ list_for_each_entry_safe(pointer, tmp, &gray_list, gray_list) {
+ list_del(&pointer->gray_list);
+ put_pointer(pointer);
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void *memleak_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ struct memleak_pointer *pointer;
+ loff_t n = *pos;
+ unsigned long flags;
+
+ mutex_lock(&memleak_mutex);
+
+ if (!n)
+ memleak_scan();
+
+ spin_lock_irqsave(&memleak_lock, flags);
+
+ list_for_each_entry(pointer, &pointer_list, pointer_list)
+ if (!n--) {
+ get_pointer(pointer);
+ goto out;
+ }
+ pointer = NULL;
+
+ out:
+ spin_unlock_irqrestore(&memleak_lock, flags);
+ return pointer;
+}
+
+static void *memleak_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct list_head *n;
+ struct memleak_pointer *next = NULL;
+ unsigned long flags;
+
+ ++(*pos);
+
+ spin_lock_irqsave(&memleak_lock, flags);
+
+ n = ((struct memleak_pointer *)v)->pointer_list.next;
+ if (n != &pointer_list) {
+ next = list_entry(n, struct memleak_pointer, pointer_list);
+ get_pointer(next);
+ }
+
+ spin_unlock_irqrestore(&memleak_lock, flags);
+
+ put_pointer(v);
+ return next;
+}
+
+static void memleak_seq_stop(struct seq_file *seq, void *v)
+{
+ if (v)
+ put_pointer(v);
+ mutex_unlock(&memleak_mutex);
+}
+
+static int memleak_seq_show(struct seq_file *seq, void *v)
+{
+ const struct memleak_pointer *pointer = v;
+#ifdef CONFIG_KALLSYMS
+ char namebuf[KSYM_NAME_LEN + 1] = "";
+ char *modname;
+ unsigned long symsize;
+ unsigned long offset = 0;
+#endif
+ int i;
+
+ if (!color_white(pointer))
+ return 0;
+ /* freed in the meantime (false positive) */
+ if (!pointer->pointer)
+ return 0;
+
+ seq_printf(seq, "orphan pointer 0x%08lx (size %d):\n",
+ pointer->pointer, pointer->size);
+
+ for (i = 0; i < MAX_TRACE; i++) {
+ unsigned long trace = pointer->trace[i];
+ if (!trace)
+ break;
+
+#ifdef CONFIG_KALLSYMS
+ kallsyms_lookup(trace, &symsize, &offset, &modname, namebuf);
+ seq_printf(seq, " %lx: <%s>\n", trace, namebuf);
+#else
+ seq_printf(seq, " %lx\n", trace);
+#endif
+ }
+
+ return 0;
+}
+
+static struct seq_operations memleak_seq_ops = {
+ .start = memleak_seq_start,
+ .next = memleak_seq_next,
+ .stop = memleak_seq_stop,
+ .show = memleak_seq_show,
+};
+
+static int memleak_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &memleak_seq_ops);
+}
+
+static struct file_operations memleak_fops = {
+ .owner = THIS_MODULE,
+ .open = memleak_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+#endif /* CONFIG_DEBUG_FS */
+
+/* KMemLeak initialization. Set up the radix tree for the pointer aliases */
+void __init memleak_init(void)
+{
+ int i;
+ unsigned long flags;
+
+ pointer_cache = kmem_cache_create("pointer_cache", sizeof(struct memleak_pointer),
+ 0, SLAB_PANIC, NULL, NULL);
+ if (!pointer_cache)
+ panic("kmemleak: cannot create the pointer cache\n");
+
+ memleak_insert_aliases(__memleak_offsets_start, __memleak_offsets_end);
+
+ /* no need to hold the spinlock as SMP is not initialized
+ * yet. Holding it here would lead to a deadlock */
+ local_irq_save(flags);
+
+ atomic_set(&memleak_initialized, 1);
+
+ /* execute the buffered memleak actions */
+ pr_debug("kmemleak: %d preinit actions\n", preinit_pos);
+ for (i = 0; i < preinit_pos; i++) {
+ struct memleak_preinit_pointer *pointer = &preinit_pointers[i];
+
+ switch (pointer->type) {
+ case MEMLEAK_ALLOC:
+ memleak_alloc(pointer->pointer, pointer->size,
+ pointer->ref_count);
+ break;
+ case MEMLEAK_FREE:
+ memleak_free(pointer->pointer);
+ break;
+ case MEMLEAK_PADDING:
+ memleak_padding(pointer->pointer, pointer->offset,
+ pointer->size);
+ break;
+ case MEMLEAK_NOT_LEAK:
+ memleak_not_leak(pointer->pointer);
+ break;
+ case MEMLEAK_IGNORE:
+ memleak_ignore(pointer->pointer);
+ break;
+ case MEMLEAK_SCAN_AREA:
+ memleak_scan_area(pointer->pointer,
+ pointer->offset, pointer->size);
+ break;
+ case MEMLEAK_TYPEID:
+ memleak_typeid_raw(pointer->pointer, pointer->type_id);
+ break;
+ default:
+ BUG();
+ }
+ }
+
+ local_irq_restore(flags);
+
+ printk(KERN_INFO "Kernel memory leak detector initialized\n");
+}
+
+/* Late initialization function */
+int __init memleak_late_init(void)
+{
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dentry;
+
+ dentry = debugfs_create_file("memleak", S_IRUGO, NULL, NULL,
+ &memleak_fops);
+ if (!dentry)
+ return -ENOMEM;
+#endif
+ pr_debug("kmemleak: late initialization completed\n");
+
+ return 0;
+}
+late_initcall(memleak_late_init);
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [PATCH 02/10] Some documentation for kmemleak
2006-07-10 22:09 [PATCH 00/10] Kernel memory leak detector 0.8 Catalin Marinas
2006-07-10 22:09 ` [PATCH 01/10] Base support for kmemleak Catalin Marinas
@ 2006-07-10 22:09 ` Catalin Marinas
2006-07-10 22:09 ` [PATCH 03/10] Add the memory allocation/freeing hooks " Catalin Marinas
` (8 subsequent siblings)
10 siblings, 0 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-10 22:09 UTC (permalink / raw)
To: linux-kernel
From: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
Documentation/kmemleak.txt | 157 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 157 insertions(+), 0 deletions(-)
diff --git a/Documentation/kmemleak.txt b/Documentation/kmemleak.txt
new file mode 100644
index 0000000..4d2f608
--- /dev/null
+++ b/Documentation/kmemleak.txt
@@ -0,0 +1,157 @@
+Kernel Memory Leak Detector
+===========================
+
+
+Introduction
+------------
+
+Kmemleak provides a way of detecting possible kernel memory leaks in a
+way similar to a tracing garbage collector
+(http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29#Tracing_garbage_collectors),
+with the difference that the orphan pointers are not freed but only
+reported via /sys/kernel/debug/memleak. A similar method is used by
+the Valgrind tool (memcheck --leak-check) to detect the memory leaks
+in user-space applications.
+
+
+Usage
+-----
+
+CONFIG_DEBUG_MEMLEAK has to be enabled. For additional config options,
+look in:
+
+ -> Kernel hacking
+ -> Kernel debugging
+ -> Debug slab memory allocations
+ -> Kernel memory leak detector
+
+To display the possible memory leaks:
+
+ # mount -t debugfs nodev /sys/kernel/debug/
+ # cat /sys/kernel/debug/memleak
+
+In order to reduce the run-time overhead, memory scanning is only
+performed when reading the /sys/kernel/debug/memleak file.
+
+
+Basic Algorithm
+---------------
+
+The memory allocations via kmalloc, vmalloc, kmem_cache_alloc and
+friends are tracked and the pointers, together with additional
+information like size and stack trace, are stored in a radix tree. The
+corresponding freeing function calls are tracked and the pointers
+removed from the radix tree.
+
+An allocated block of memory is considered orphan if a pointer to its
+start address or to an alias (pointer aliases are explained later)
+cannot be found by scanning the memory (including saved
+registers). This means that there might be no way for the kernel to
+pass the address of the allocated block to a freeing function and
+therefore the block is considered a leak.
+
+The scanning algorithm steps:
+
+ 1. mark all pointers as white (remaining white pointers will later
+ be considered orphan)
+ 2. scan the memory starting with the data section and stacks,
+ checking the values against the addresses stored in the radix
+ tree. If a white pointer is found, it is added to the grey list
+ 3. scan the grey pointers for matching addresses (some white
+ pointers can become grey and added at the end of the grey list)
+ until the grey set is finished
+ 4. the remaining white pointers are considered orphan and reported
+ via /sys/kernel/debug/memleak
+
+
+Improvements
+------------
+
+Because the Linux kernel calculates many pointers at run-time via the
+container_of macro (see the lists implementation), a lot of false
+positives would be reported. This tool re-writes the container_of
+macro so that the offset and type information is stored in the
+.init.memleak_offsets section. The memleak_init() function creates a
+radix tree with corresponding offsets for every encountered block
+type. The memory allocations hook stores the pointer address together
+with its aliases based on the type of the allocated block.
+
+While one level of offsets should be enough for most cases, a second
+level, i.e. container_of(container_of(...)), can be enabled via the
+configuration options (one false positive is the "struct socket_alloc"
+allocation in the sock_alloc_inode() function).
+
+Some allocated memory blocks have pointers stored in the kernel's
+internal data structures and they cannot be detected as orphans. To
+avoid this, kmemleak can also store the number of values equal to the
+pointer (or aliases) that need to be found so that the block is not
+considered a leak. One example is __vmalloc().
+
+
+Limitations and Drawbacks
+-------------------------
+
+The biggest drawback is the reduced performance of memory allocation
+and freeing. To avoid other penalties, the memory scanning is only
+performed when the /sys/kernel/debug/memleak file is read. Anyway,
+this tool is intended for debugging purposes where the performance
+might not be the most important requirement.
+
+Kmemleak currently approximates the type id using the sizeof()
+compiler built-in function. This is not accurate and can lead to false
+negatives. The aim is to gradually change the kernel and kmemleak to
+do more precise type identification.
+
+Another source of false negatives is the data stored in non-pointer
+values. Together with the more precise type identification, kmemleak
+could only scan the pointer members in the allocated structures.
+
+The tool can report false positives. These are cases where an
+allocated block doesn't need to be freed (some cases in the init_call
+functions), the pointer is calculated by other methods than the
+container_of macro or the pointer is stored in a location not scanned
+by kmemleak. If the "member" argument in the offsetof(type, member)
+call is not constant, kmemleak considers the offset as zero since it
+cannot be determined at compilation time.
+
+Page allocations and ioremap are not tracked. Only the ARM and i386
+architectures are currently supported.
+
+
+Kmemleak API
+------------
+
+See the include/linux/memleak.h header for the functions prototype.
+
+memleak_init - initialize kmemleak
+memleak_alloc - notify of a memory block allocation
+memleak_free - notify of a memory block freeing
+memleak_padding - mark the boundaries of the data inside the block
+memleak_not_leak - mark a pointer as not a leak
+memleak_ignore - do not scan or report a pointer as leak
+memleak_scan_area - add scan areas inside a memory block
+memleak_insert_aliases - add aliases for a given type
+memleak_erase - erase an old value in a pointer variable
+memleak_typeid_raw - set the typeid for an allocated block
+memleak_container - statically declare a pointer alias
+memleak_typeid - set the typeid for an allocated block (takes
+ a type rather than typeid as argument)
+
+
+Dealing with false positives/negatives
+--------------------------------------
+
+To reduce the false negatives, kmemleak provides the memleak_ignore,
+memleak_scan_area and memleak_erase functions. The task stacks also
+increase the amount of false negatives and their scanning is not
+enabled by default.
+
+To eliminate the false positives caused by code allocating a different
+size from the object one (either for alignment or for extra memory
+after the end of the structure), kmemleak provides the memleak_padding
+and memleak_typeid functions.
+
+For pointers known not to be leaks, kmemleak provides the
+memleak_not_leak function. The memleak_ignore could also be used if
+the memory block is known not to contain other pointers as it will no
+longer be scanned.
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [PATCH 03/10] Add the memory allocation/freeing hooks for kmemleak
2006-07-10 22:09 [PATCH 00/10] Kernel memory leak detector 0.8 Catalin Marinas
2006-07-10 22:09 ` [PATCH 01/10] Base support for kmemleak Catalin Marinas
2006-07-10 22:09 ` [PATCH 02/10] Some documentation " Catalin Marinas
@ 2006-07-10 22:09 ` Catalin Marinas
2006-07-11 6:17 ` Pekka Enberg
2006-07-10 22:10 ` [PATCH 04/10] Modules support " Catalin Marinas
` (7 subsequent siblings)
10 siblings, 1 reply; 49+ messages in thread
From: Catalin Marinas @ 2006-07-10 22:09 UTC (permalink / raw)
To: linux-kernel
From: Catalin Marinas <catalin.marinas@arm.com>
This patch adds the callbacks to memleak_(alloc|free) functions from
kmalloc/kfree, kmem_cache_(alloc|free), vmalloc/vfree etc.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
include/linux/slab.h | 6 ++++++
mm/page_alloc.c | 2 ++
mm/slab.c | 26 +++++++++++++++++++++++---
mm/vmalloc.c | 22 ++++++++++++++++++++--
4 files changed, 51 insertions(+), 5 deletions(-)
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 45ad55b..e3f5945 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -133,6 +133,8 @@ #endif
*/
static inline void *kmalloc(size_t size, gfp_t flags)
{
+#ifndef CONFIG_DEBUG_MEMLEAK
+ /* this block removes the size information needed by kmemleak */
if (__builtin_constant_p(size)) {
int i = 0;
#define CACHE(x) \
@@ -151,6 +153,7 @@ found:
malloc_sizes[i].cs_dmacachep :
malloc_sizes[i].cs_cachep, flags);
}
+#endif
return __kmalloc(size, flags);
}
@@ -163,6 +166,8 @@ extern void *__kzalloc(size_t, gfp_t);
*/
static inline void *kzalloc(size_t size, gfp_t flags)
{
+#ifndef CONFIG_DEBUG_MEMLEAK
+ /* this block removes the size information needed by kmemleak */
if (__builtin_constant_p(size)) {
int i = 0;
#define CACHE(x) \
@@ -181,6 +186,7 @@ found:
malloc_sizes[i].cs_dmacachep :
malloc_sizes[i].cs_cachep, flags);
}
+#endif
return __kzalloc(size, flags);
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 54a4f53..bdf6445 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2450,6 +2450,8 @@ void *__init alloc_large_system_hash(con
if (_hash_mask)
*_hash_mask = (1 << log2qty) - 1;
+ memleak_alloc(table, size, 1);
+
return table;
}
diff --git a/mm/slab.c b/mm/slab.c
index 85c2e03..2752272 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2967,6 +2967,7 @@ #endif
STATS_INC_ALLOCMISS(cachep);
objp = cache_alloc_refill(cachep, flags);
}
+ memleak_erase(&ac->entry[ac->avail]);
return objp;
}
@@ -3183,6 +3184,7 @@ static void __cache_free(struct kmem_cac
struct array_cache *ac = cpu_cache_get(cachep);
check_irq_off();
+ memleak_free(objp);
objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));
if (cache_free_alien(cachep, objp, nesting))
@@ -3209,7 +3211,11 @@ static void __cache_free(struct kmem_cac
*/
void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
{
- return __cache_alloc(cachep, flags, __builtin_return_address(0));
+ void *ptr = __cache_alloc(cachep, flags, __builtin_return_address(0));
+
+ memleak_alloc(ptr, obj_size(cachep), 1);
+
+ return ptr;
}
EXPORT_SYMBOL(kmem_cache_alloc);
@@ -3224,6 +3230,9 @@ EXPORT_SYMBOL(kmem_cache_alloc);
void *kmem_cache_zalloc(struct kmem_cache *cache, gfp_t flags)
{
void *ret = __cache_alloc(cache, flags, __builtin_return_address(0));
+
+ memleak_alloc(ret, obj_size(cache), 1);
+
if (ret)
memset(ret, 0, obj_size(cache));
return ret;
@@ -3302,6 +3311,7 @@ void *kmem_cache_alloc_node(struct kmem_
ptr = cache_alloc_debugcheck_after(cachep, flags, ptr,
__builtin_return_address(0));
+ memleak_alloc(ptr, obj_size(cachep), 1);
return ptr;
}
@@ -3310,11 +3320,15 @@ EXPORT_SYMBOL(kmem_cache_alloc_node);
void *kmalloc_node(size_t size, gfp_t flags, int node)
{
struct kmem_cache *cachep;
+ void *ptr;
cachep = kmem_find_general_cachep(size, flags);
if (unlikely(cachep == NULL))
return NULL;
- return kmem_cache_alloc_node(cachep, flags, node);
+ ptr = kmem_cache_alloc_node(cachep, flags, node);
+ memleak_typeid_raw(ptr, ml_guess_typeid(size));
+ memleak_padding(ptr, 0, size);
+ return ptr;
}
EXPORT_SYMBOL(kmalloc_node);
#endif
@@ -3329,6 +3343,7 @@ static __always_inline void *__do_kmallo
void *caller)
{
struct kmem_cache *cachep;
+ void *ptr;
/* If you want to save a few bytes .text space: replace
* __ with kmem_.
@@ -3338,7 +3353,11 @@ static __always_inline void *__do_kmallo
cachep = __find_general_cachep(size, flags);
if (unlikely(cachep == NULL))
return NULL;
- return __cache_alloc(cachep, flags, caller);
+ ptr = __cache_alloc(cachep, flags, caller);
+
+ memleak_alloc(ptr, size, 1);
+
+ return ptr;
}
@@ -3447,6 +3466,7 @@ void kfree(const void *objp)
return;
local_irq_save(flags);
kfree_debugcheck(objp);
+
c = virt_to_cache(objp);
debug_check_no_locks_freed(objp, obj_size(c));
__cache_free(c, (void *)objp, 0);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 7b45079..b84a862 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -364,6 +364,9 @@ void __vunmap(void *addr, int deallocate
void vfree(void *addr)
{
BUG_ON(in_interrupt());
+
+ memleak_free(addr);
+
__vunmap(addr, 1);
}
EXPORT_SYMBOL(vfree);
@@ -462,7 +465,14 @@ fail:
void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot)
{
- return __vmalloc_area_node(area, gfp_mask, prot, -1);
+ void *addr = __vmalloc_area_node(area, gfp_mask, prot, -1);
+
+ /* this needs ref_count = 2 since vm_struct also contains a
+ pointer to this address. The guard page is also subtracted
+ from the size */
+ memleak_alloc(addr, area->size - PAGE_SIZE, 2);
+
+ return addr;
}
/**
@@ -481,6 +491,8 @@ void *__vmalloc_node(unsigned long size,
int node)
{
struct vm_struct *area;
+ void *addr;
+ unsigned long real_size = size;
size = PAGE_ALIGN(size);
if (!size || (size >> PAGE_SHIFT) > num_physpages)
@@ -490,7 +502,13 @@ void *__vmalloc_node(unsigned long size,
if (!area)
return NULL;
- return __vmalloc_area_node(area, gfp_mask, prot, node);
+ addr = __vmalloc_area_node(area, gfp_mask, prot, node);
+
+ /* this needs ref_count = 2 since the vm_struct also contains
+ a pointer to this address */
+ memleak_alloc(addr, real_size, 2);
+
+ return addr;
}
EXPORT_SYMBOL(__vmalloc_node);
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [PATCH 04/10] Modules support for kmemleak
2006-07-10 22:09 [PATCH 00/10] Kernel memory leak detector 0.8 Catalin Marinas
` (2 preceding siblings ...)
2006-07-10 22:09 ` [PATCH 03/10] Add the memory allocation/freeing hooks " Catalin Marinas
@ 2006-07-10 22:10 ` Catalin Marinas
2006-07-10 22:10 ` [PATCH 05/10] Add kmemleak support for i386 Catalin Marinas
` (6 subsequent siblings)
10 siblings, 0 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-10 22:10 UTC (permalink / raw)
To: linux-kernel
From: Catalin Marinas <catalin.marinas@arm.com>
This patch handles the kmemleak operations needed for modules loading so
that memory allocations from inside a module are properly tracked.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
kernel/module.c | 41 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 41 insertions(+), 0 deletions(-)
diff --git a/kernel/module.c b/kernel/module.c
index 35e1b1f..3b88c06 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1481,6 +1481,11 @@ static struct module *load_module(void _
unsigned int unusedcrcindex;
unsigned int unusedgplindex;
unsigned int unusedgplcrcindex;
+#ifdef CONFIG_DEBUG_MEMLEAK
+ unsigned int dataindex;
+ unsigned int bssindex;
+ unsigned int mloffindex;
+#endif
struct module *mod;
long err = 0;
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1577,6 +1582,11 @@ #endif
#ifdef ARCH_UNWIND_SECTION_NAME
unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
#endif
+#ifdef CONFIG_DEBUG_MEMLEAK
+ dataindex = find_sec(hdr, sechdrs, secstrings, ".data");
+ bssindex = find_sec(hdr, sechdrs, secstrings, ".bss");
+ mloffindex = find_sec(hdr, sechdrs, secstrings, ".init.memleak_offsets");
+#endif
/* Don't keep modinfo section */
sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
@@ -1646,6 +1656,10 @@ #endif
/* Do the allocs. */
ptr = module_alloc(mod->core_size);
+ /* the pointer to this block is stored in the module structure
+ * which is inside the block. Just mark it as not being a
+ * leak */
+ memleak_not_leak(ptr);
if (!ptr) {
err = -ENOMEM;
goto free_percpu;
@@ -1654,6 +1668,11 @@ #endif
mod->module_core = ptr;
ptr = module_alloc(mod->init_size);
+ /* the pointer to this block is stored in the module structure
+ * which is inside the block. This block doesn't need to be
+ * scanned as it contains data and code that will be freed
+ * after the module is initialized */
+ memleak_ignore(ptr);
if (!ptr && mod->init_size) {
err = -ENOMEM;
goto free_core;
@@ -1685,6 +1704,28 @@ #endif
/* Module has been moved. */
mod = (void *)sechdrs[modindex].sh_addr;
+#ifdef CONFIG_DEBUG_MEMLEAK
+ if (mloffindex)
+ memleak_insert_aliases((void *)sechdrs[mloffindex].sh_addr,
+ (void *)sechdrs[mloffindex].sh_addr
+ + sechdrs[mloffindex].sh_size);
+
+ /* only scan the sections containing data */
+ memleak_scan_area(mod->module_core,
+ (unsigned long)mod - (unsigned long)mod->module_core,
+ sizeof(struct module));
+ if (dataindex)
+ memleak_scan_area(mod->module_core,
+ sechdrs[dataindex].sh_addr
+ - (unsigned long)mod->module_core,
+ sechdrs[dataindex].sh_size);
+ if (bssindex)
+ memleak_scan_area(mod->module_core,
+ sechdrs[bssindex].sh_addr
+ - (unsigned long)mod->module_core,
+ sechdrs[bssindex].sh_size);
+#endif
+
/* Now we've moved module, initialize linked lists, etc. */
module_unload_init(mod);
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [PATCH 05/10] Add kmemleak support for i386
2006-07-10 22:09 [PATCH 00/10] Kernel memory leak detector 0.8 Catalin Marinas
` (3 preceding siblings ...)
2006-07-10 22:10 ` [PATCH 04/10] Modules support " Catalin Marinas
@ 2006-07-10 22:10 ` Catalin Marinas
2006-07-10 22:10 ` [PATCH 06/10] Add kmemleak support for ARM Catalin Marinas
` (5 subsequent siblings)
10 siblings, 0 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-10 22:10 UTC (permalink / raw)
To: linux-kernel
From: Catalin Marinas <catalin.marinas@arm.com>
This patch modifies the vmlinux.lds.S script and adds the backtrace support
for i386 to be used with kmemleak.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/i386/kernel/vmlinux.lds.S | 4 ++++
include/asm-i386/processor.h | 12 ++++++++++++
include/asm-i386/thread_info.h | 10 +++++++++-
3 files changed, 25 insertions(+), 1 deletions(-)
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index 2d4f138..34fccf1 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -45,6 +45,7 @@ SECTIONS
__tracedata_end = .;
/* writeable */
+ _sdata = .; /* Start of data section */
.data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */
*(.data)
CONSTRUCTORS
@@ -156,6 +157,9 @@ #endif
__per_cpu_start = .;
.data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
__per_cpu_end = .;
+ __memleak_offsets_start = .;
+ .init.memleak_offsets : AT(ADDR(.init.memleak_offsets) - LOAD_OFFSET) { *(.init.memleak_offsets) }
+ __memleak_offsets_end = .;
. = ALIGN(4096);
__init_end = .;
/* freed after init ends here */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index b32346d..0884122 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -731,4 +731,16 @@ extern unsigned long boot_option_idle_ov
extern void enable_sep_cpu(void);
extern int sysenter_setup(void);
+#ifdef CONFIG_FRAME_POINTER
+static inline unsigned long arch_call_address(void *frame)
+{
+ return *(unsigned long *) (frame + 4);
+}
+
+static inline void *arch_prev_frame(void *frame)
+{
+ return *(void **) frame;
+}
+#endif
+
#endif /* __ASM_I386_PROCESSOR_H */
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
index 2833fa2..80b9451 100644
--- a/include/asm-i386/thread_info.h
+++ b/include/asm-i386/thread_info.h
@@ -100,12 +100,20 @@ #define alloc_thread_info(tsk) \
struct thread_info *ret; \
\
ret = kmalloc(THREAD_SIZE, GFP_KERNEL); \
+ memleak_ignore(ret); \
if (ret) \
memset(ret, 0, THREAD_SIZE); \
ret; \
})
#else
-#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL)
+#define alloc_thread_info(tsk) \
+ ({ \
+ struct thread_info *ret; \
+ \
+ ret = kmalloc(THREAD_SIZE, GFP_KERNEL); \
+ memleak_ignore(ret); \
+ ret; \
+ })
#endif
#define free_thread_info(info) kfree(info)
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [PATCH 06/10] Add kmemleak support for ARM
2006-07-10 22:09 [PATCH 00/10] Kernel memory leak detector 0.8 Catalin Marinas
` (4 preceding siblings ...)
2006-07-10 22:10 ` [PATCH 05/10] Add kmemleak support for i386 Catalin Marinas
@ 2006-07-10 22:10 ` Catalin Marinas
2006-07-10 22:10 ` [PATCH 07/10] Remove some of the kmemleak false positives Catalin Marinas
` (4 subsequent siblings)
10 siblings, 0 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-10 22:10 UTC (permalink / raw)
To: linux-kernel
From: Catalin Marinas <catalin.marinas@arm.com>
This patch modifies the vmlinux.lds.S script and adds the backtrace support
for ARM to be used with kmemleak.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm/kernel/vmlinux.lds.S | 7 +++++++
include/asm-arm/processor.h | 12 ++++++++++++
2 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 3ca574e..59976b8 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -67,6 +67,11 @@ #endif
__per_cpu_start = .;
*(.data.percpu)
__per_cpu_end = .;
+#ifdef CONFIG_DEBUG_MEMLEAK
+ __memleak_offsets_start = .;
+ *(.init.memleak_offsets)
+ __memleak_offsets_end = .;
+#endif
#ifndef CONFIG_XIP_KERNEL
__init_begin = _stext;
*(.init.data)
@@ -115,6 +120,7 @@ #endif
.data : AT(__data_loc) {
__data_start = .; /* address in memory */
+ _sdata = .;
/*
* first, the init task union, aligned
@@ -165,6 +171,7 @@ #endif
__bss_start = .; /* BSS */
*(.bss)
*(COMMON)
+ __bss_stop = .;
_end = .;
}
/* Stabs debugging sections. */
diff --git a/include/asm-arm/processor.h b/include/asm-arm/processor.h
index 04f4d34..feaf017 100644
--- a/include/asm-arm/processor.h
+++ b/include/asm-arm/processor.h
@@ -121,6 +121,18 @@ #define spin_lock_prefetch(x) do { } whi
#endif
+#ifdef CONFIG_FRAME_POINTER
+static inline unsigned long arch_call_address(void *frame)
+{
+ return *(unsigned long *) (frame - 4) - 4;
+}
+
+static inline void *arch_prev_frame(void *frame)
+{
+ return *(void **) (frame - 12);
+}
+#endif
+
#endif
#endif /* __ASM_ARM_PROCESSOR_H */
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [PATCH 07/10] Remove some of the kmemleak false positives
2006-07-10 22:09 [PATCH 00/10] Kernel memory leak detector 0.8 Catalin Marinas
` (5 preceding siblings ...)
2006-07-10 22:10 ` [PATCH 06/10] Add kmemleak support for ARM Catalin Marinas
@ 2006-07-10 22:10 ` Catalin Marinas
2006-07-11 6:49 ` Pekka Enberg
2006-07-10 22:10 ` [PATCH 08/10] Keep the __init functions after initialization Catalin Marinas
` (3 subsequent siblings)
10 siblings, 1 reply; 49+ messages in thread
From: Catalin Marinas @ 2006-07-10 22:10 UTC (permalink / raw)
To: linux-kernel
From: Catalin Marinas <catalin.marinas@arm.com>
There are allocations for which the main pointer cannot be found but they
are not memory leaks. This patch fixes some of them.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
drivers/base/platform.c | 3 +++
drivers/hwmon/w83627hf.c | 4 ++++
drivers/scsi/hosts.c | 3 +++
fs/ext3/dir.c | 3 +++
ipc/util.c | 6 ++++++
kernel/params.c | 8 +++++++-
mm/slab.c | 4 ++++
net/core/dev.c | 6 ++++++
net/sched/sch_generic.c | 6 ++++++
9 files changed, 42 insertions(+), 1 deletions(-)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 2b8755d..1521fe4 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -166,6 +166,9 @@ struct platform_device *platform_device_
struct platform_object *pa;
pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL);
+ /* kmemleak cannot guess the object type because the block
+ * size is different from the object size */
+ memleak_typeid(pa, struct platform_object);
if (pa) {
strcpy(pa->name, name);
pa->pdev.name = pa->name;
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 79368d5..f952f02 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -1065,6 +1065,10 @@ static int w83627hf_detect(struct i2c_ad
err = -ENOMEM;
goto ERROR1;
}
+ /* the pointer to member is stored but the code doesn't use
+ * container_of for access and the alias need to be
+ * explicitely declared here */
+ memleak_container(struct w83627hf_data, client);
new_client = &data->client;
i2c_set_clientdata(new_client, data);
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index dfcb96f..9516d37 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -297,6 +297,9 @@ struct Scsi_Host *scsi_host_alloc(struct
shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
if (!shost)
return NULL;
+ /* kmemleak cannot guess the object type because the block
+ * size is different from the object size */
+ memleak_typeid(shost, struct Scsi_Host);
spin_lock_init(&shost->default_lock);
scsi_assign_lock(shost, &shost->default_lock);
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index fbb0d4e..a34814d 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -346,6 +346,9 @@ int ext3_htree_store_dirent(struct file
new_fn = kmalloc(len, GFP_KERNEL);
if (!new_fn)
return -ENOMEM;
+ /* kmemleak cannot guess the object type because the block
+ * size is different from the object size */
+ memleak_typeid(new_fn, struct fname);
memset(new_fn, 0, len);
new_fn->hash = hash;
new_fn->minor_hash = minor_hash;
diff --git a/ipc/util.c b/ipc/util.c
index 67b6d17..17cc294 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -388,6 +388,9 @@ void* ipc_rcu_alloc(int size)
*/
if (rcu_use_vmalloc(size)) {
out = vmalloc(HDRLEN_VMALLOC + size);
+ /* the stored pointer is different from the address of
+ * the allocated block because of padding */
+ memleak_padding(out, HDRLEN_VMALLOC, size);
if (out) {
out += HDRLEN_VMALLOC;
container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 1;
@@ -395,6 +398,9 @@ void* ipc_rcu_alloc(int size)
}
} else {
out = kmalloc(HDRLEN_KMALLOC + size, GFP_KERNEL);
+ /* the stored pointer is different from the address of
+ * the allocated block because of padding */
+ memleak_padding(out, HDRLEN_KMALLOC, size);
if (out) {
out += HDRLEN_KMALLOC;
container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 0;
diff --git a/kernel/params.c b/kernel/params.c
index 91aea7a..b957b86 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -547,6 +547,7 @@ static void __init kernel_param_sysfs_se
unsigned int name_skip)
{
struct module_kobject *mk;
+ struct module_param_attrs *mp;
mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL);
BUG_ON(!mk);
@@ -556,8 +557,13 @@ static void __init kernel_param_sysfs_se
kobject_set_name(&mk->kobj, name);
kobject_register(&mk->kobj);
+ mp = param_sysfs_setup(mk, kparam, num_params, name_skip);
+ /* this structure is not freed but the pointer is
+ * lost. However, there are other pointers to its members and
+ * the object has to be kept */
+ memleak_not_leak(mp);
/* no need to keep the kobject if no parameter is exported */
- if (!param_sysfs_setup(mk, kparam, num_params, name_skip)) {
+ if (!mp) {
kobject_unregister(&mk->kobj);
kfree(mk);
}
diff --git a/mm/slab.c b/mm/slab.c
index 2752272..0949c45 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3413,6 +3413,10 @@ void *__alloc_percpu(size_t size)
memset(pdata->ptrs[i], 0, size);
}
+ /* the code below changes the value of the returned pointer
+ * and kmemleak cannot find the original value during
+ * scanning. It is marked as not being a leak */
+ memleak_not_leak(pdata);
/* Catch derefs w/o wrappers */
return (void *)(~(unsigned long)pdata);
diff --git a/net/core/dev.c b/net/core/dev.c
index 066a60a..3b30423 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3193,6 +3193,12 @@ struct net_device *alloc_netdev(int size
dev = (struct net_device *)
(((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
dev->padded = (char *)dev - (char *)p;
+ /* kmemleak cannot guess the object type because the block
+ * size is different from the object size. The stored pointer
+ * is also different from the address of the allocated block
+ * because of padding */
+ memleak_padding(p, dev->padded, sizeof(struct net_device));
+ memleak_typeid(p, struct net_device);
if (sizeof_priv)
dev->priv = netdev_priv(dev);
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index d735f51..ae3e145 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -438,6 +438,12 @@ struct Qdisc *qdisc_alloc(struct net_dev
memset(p, 0, size);
sch = (struct Qdisc *) QDISC_ALIGN((unsigned long) p);
sch->padded = (char *) sch - (char *) p;
+ /* kmemleak cannot guess the object type because the block
+ * size is different from the object size. The stored pointer
+ * is also different from the address of the allocated block
+ * because of padding */
+ memleak_padding(p, sch->padded, sizeof(struct Qdisc));
+ memleak_typeid(p, struct Qdisc);
INIT_LIST_HEAD(&sch->list);
skb_queue_head_init(&sch->q);
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [PATCH 08/10] Keep the __init functions after initialization
2006-07-10 22:09 [PATCH 00/10] Kernel memory leak detector 0.8 Catalin Marinas
` (6 preceding siblings ...)
2006-07-10 22:10 ` [PATCH 07/10] Remove some of the kmemleak false positives Catalin Marinas
@ 2006-07-10 22:10 ` Catalin Marinas
2006-07-10 22:10 ` [PATCH 09/10] Simple testing for kmemleak Catalin Marinas
` (2 subsequent siblings)
10 siblings, 0 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-10 22:10 UTC (permalink / raw)
To: linux-kernel
From: Catalin Marinas <catalin.marinas@arm.com>
This patch adds the CONFIG_DEBUG_KEEP_INIT option which preserves the
.init.text section after initialization. Memory leaks happening during this
phase can be more easily tracked.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
include/linux/init.h | 4 ++++
lib/Kconfig.debug | 10 ++++++++++
2 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/include/linux/init.h b/include/linux/init.h
index 6667785..1590e9a 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -40,7 +40,11 @@ #include <linux/compiler.h>
/* These are for everybody (although not all archs will actually
discard it in modules) */
+#ifdef CONFIG_DEBUG_KEEP_INIT
+#define __init
+#else
#define __init __attribute__ ((__section__ (".init.text")))
+#endif
#define __initdata __attribute__ ((__section__ (".init.data")))
#define __exitdata __attribute__ ((__section__(".exit.data")))
#define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 6c56be2..5013375 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -171,6 +171,16 @@ config DEBUG_MEMLEAK_ORPHAN_FREEING
information displayed allow an easier identification of
false positives.
+config DEBUG_KEEP_INIT
+ bool "Do not free the __init functions"
+ default n
+ depends on DEBUG_MEMLEAK
+ help
+ This option moves the __init functions out of the .init.text
+ section and therefore they are no longer freed after the
+ kernel initialization. It is useful for identifying memory
+ leaks happening during the kernel or modules initialization.
+
config DEBUG_PREEMPT
bool "Debug preemptible kernel"
depends on DEBUG_KERNEL && PREEMPT && TRACE_IRQFLAGS_SUPPORT
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [PATCH 09/10] Simple testing for kmemleak
2006-07-10 22:09 [PATCH 00/10] Kernel memory leak detector 0.8 Catalin Marinas
` (7 preceding siblings ...)
2006-07-10 22:10 ` [PATCH 08/10] Keep the __init functions after initialization Catalin Marinas
@ 2006-07-10 22:10 ` Catalin Marinas
2006-07-10 22:11 ` [PATCH 10/10] Update the MAINTAINERS file " Catalin Marinas
2006-07-11 12:27 ` [PATCH 00/10] Kernel memory leak detector 0.8 Michal Piotrowski
10 siblings, 0 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-10 22:10 UTC (permalink / raw)
To: linux-kernel
From: Catalin Marinas <catalin.marinas@arm.com>
This patch only contains some very simple testing at the moment. Proper
testing will be needed.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
lib/Kconfig.debug | 9 ++++++
mm/Makefile | 1 +
mm/memleak-test.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 93 insertions(+), 0 deletions(-)
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 5013375..5240d62 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -181,6 +181,15 @@ config DEBUG_KEEP_INIT
kernel initialization. It is useful for identifying memory
leaks happening during the kernel or modules initialization.
+config DEBUG_MEMLEAK_TEST
+ tristate "Test the kernel memory leak detector"
+ default n
+ depends on DEBUG_MEMLEAK
+ help
+ Say Y here to build the test harness for the kernel memory
+ leak detector. At the moment, this option enables a module
+ that explicitly leaks memory.
+
config DEBUG_PREEMPT
bool "Debug preemptible kernel"
depends on DEBUG_KERNEL && PREEMPT && TRACE_IRQFLAGS_SUPPORT
diff --git a/mm/Makefile b/mm/Makefile
index edccbc0..fd46a73 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_MEMORY_HOTPLUG) += memory_h
obj-$(CONFIG_FS_XIP) += filemap_xip.o
obj-$(CONFIG_MIGRATION) += migrate.o
obj-$(CONFIG_DEBUG_MEMLEAK) += memleak.o
+obj-$(CONFIG_DEBUG_MEMLEAK_TEST) += memleak-test.o
diff --git a/mm/memleak-test.c b/mm/memleak-test.c
new file mode 100644
index 0000000..4061f99
--- /dev/null
+++ b/mm/memleak-test.c
@@ -0,0 +1,83 @@
+/*
+ * mm/memleak-test.c
+ *
+ * Copyright (C) 2006 ARM Limited
+ * Written by Catalin Marinas <catalin.marinas@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/list.h>
+
+#include <linux/memleak.h>
+
+struct test_node {
+ long header[25];
+ struct list_head list;
+ long footer[25];
+};
+
+static LIST_HEAD(test_list);
+
+/* Some very simple testing. This function needs to be extended for
+ * proper testing */
+static int __init memleak_test_init(void)
+{
+ struct test_node *elem;
+ int i;
+
+ printk(KERN_INFO "KMemLeak testing\n");
+
+ /* make some orphan pointers */
+ kmalloc(32, GFP_KERNEL);
+ kmalloc(32, GFP_KERNEL);
+#ifndef CONFIG_MODULES
+ kmem_cache_alloc(files_cachep, GFP_KERNEL);
+ kmem_cache_alloc(files_cachep, GFP_KERNEL);
+#endif
+ vmalloc(64);
+ vmalloc(64);
+
+ /* add elements to a list. They should only appear as orphan
+ * after the module is removed */
+ for (i = 0; i < 10; i++) {
+ elem = kmalloc(sizeof(*elem), GFP_KERNEL);
+ if (!elem)
+ return -ENOMEM;
+ memset(elem, 0, sizeof(*elem));
+ INIT_LIST_HEAD(&elem->list);
+
+ list_add_tail(&elem->list, &test_list);
+ }
+
+ return 0;
+}
+module_init(memleak_test_init);
+
+static void __exit memleak_test_exit(void)
+{
+ struct test_node *elem, *tmp;
+
+ /* remove the list elements without actually freeing the memory */
+ list_for_each_entry_safe(elem, tmp, &test_list, list)
+ list_del(&elem->list);
+}
+module_exit(memleak_test_exit);
+
+MODULE_LICENSE("GPL");
^ permalink raw reply related [flat|nested] 49+ messages in thread
* [PATCH 10/10] Update the MAINTAINERS file for kmemleak
2006-07-10 22:09 [PATCH 00/10] Kernel memory leak detector 0.8 Catalin Marinas
` (8 preceding siblings ...)
2006-07-10 22:10 ` [PATCH 09/10] Simple testing for kmemleak Catalin Marinas
@ 2006-07-10 22:11 ` Catalin Marinas
2006-07-11 12:27 ` [PATCH 00/10] Kernel memory leak detector 0.8 Michal Piotrowski
10 siblings, 0 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-10 22:11 UTC (permalink / raw)
To: linux-kernel
From: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
MAINTAINERS | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 196a31c..808b75e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1635,6 +1635,12 @@ W: http://www.kerneljanitors.org/
W: http://sf.net/projects/kernel-janitor/
S: Maintained
+KERNEL MEMORY LEAK DETECTOR
+P: Catalin Marinas
+M: catalin.marinas@gmail.com
+W: http://www.procode.org/
+S: Maintained
+
KERNEL NFSD
P: Neil Brown
M: neilb@cse.unsw.edu.au
^ permalink raw reply related [flat|nested] 49+ messages in thread
* Re: [PATCH 03/10] Add the memory allocation/freeing hooks for kmemleak
2006-07-10 22:09 ` [PATCH 03/10] Add the memory allocation/freeing hooks " Catalin Marinas
@ 2006-07-11 6:17 ` Pekka Enberg
2006-07-11 7:59 ` Catalin Marinas
0 siblings, 1 reply; 49+ messages in thread
From: Pekka Enberg @ 2006-07-11 6:17 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
Hi Catalin
On 7/11/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> diff --git a/mm/slab.c b/mm/slab.c
> index 85c2e03..2752272 100644
> --- a/mm/slab.c
> +++ b/mm/slab.c
> @@ -2967,6 +2967,7 @@ #endif
> STATS_INC_ALLOCMISS(cachep);
> objp = cache_alloc_refill(cachep, flags);
> }
> + memleak_erase(&ac->entry[ac->avail]);
> return objp;
> }
Can't we tell the GC not to scan any of the array cache structs? You
could put that in alloc_arraycache(), I think.
> @@ -3209,7 +3211,11 @@ static void __cache_free(struct kmem_cac
> */
> void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
> {
> - return __cache_alloc(cachep, flags, __builtin_return_address(0));
> + void *ptr = __cache_alloc(cachep, flags, __builtin_return_address(0));
> +
> + memleak_alloc(ptr, obj_size(cachep), 1);
Can you move memleak_alloc() call to __cache_alloc() instead to avoid
duplication?
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 07/10] Remove some of the kmemleak false positives
2006-07-10 22:10 ` [PATCH 07/10] Remove some of the kmemleak false positives Catalin Marinas
@ 2006-07-11 6:49 ` Pekka Enberg
2006-07-11 8:18 ` Catalin Marinas
0 siblings, 1 reply; 49+ messages in thread
From: Pekka Enberg @ 2006-07-11 6:49 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
On 7/11/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> @@ -166,6 +166,9 @@ struct platform_device *platform_device_
> struct platform_object *pa;
>
> pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL);
> + /* kmemleak cannot guess the object type because the block
> + * size is different from the object size */
> + memleak_typeid(pa, struct platform_object);
AFAICT, we about 300 kmalloc and kzalloc calls in the kernel that
would need this annotation. If we really can't fix the detector to
deal with these, I would prefer we introduce another memory allocator
function such as:
void *kzalloc_extra(size_t obj_size, size_t nr_extra, gfp_t flags);
That would do the right thing for memleak too.
Pekka
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 03/10] Add the memory allocation/freeing hooks for kmemleak
2006-07-11 6:17 ` Pekka Enberg
@ 2006-07-11 7:59 ` Catalin Marinas
0 siblings, 0 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-11 7:59 UTC (permalink / raw)
To: Pekka Enberg; +Cc: linux-kernel
Hi Pekka,
On 11/07/06, Pekka Enberg <penberg@cs.helsinki.fi> wrote:
> On 7/11/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> > diff --git a/mm/slab.c b/mm/slab.c
> > index 85c2e03..2752272 100644
> > --- a/mm/slab.c
> > +++ b/mm/slab.c
> > @@ -2967,6 +2967,7 @@ #endif
> > STATS_INC_ALLOCMISS(cachep);
> > objp = cache_alloc_refill(cachep, flags);
> > }
> > + memleak_erase(&ac->entry[ac->avail]);
> > return objp;
> > }
>
> Can't we tell the GC not to scan any of the array cache structs? You
> could put that in alloc_arraycache(), I think.
Yes, we can. I'll give it a try before updating the patches.
> > @@ -3209,7 +3211,11 @@ static void __cache_free(struct kmem_cac
> > */
> > void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
> > {
> > - return __cache_alloc(cachep, flags, __builtin_return_address(0));
> > + void *ptr = __cache_alloc(cachep, flags, __builtin_return_address(0));
> > +
> > + memleak_alloc(ptr, obj_size(cachep), 1);
>
> Can you move memleak_alloc() call to __cache_alloc() instead to avoid
> duplication?
It might clutter the code because __cache_alloc is used by kmalloc as
well and the exact size information is lost. It would be to
explicitely give the type information to kmemleak in kmalloc and have
memleak_alloc called in __cache_alloc (with slight overhead of calling
kmemleak functions twice). The other option is to pass an extra
argument (guessed typeid) to __cache_alloc but this means adding extra
ifdefs.
Thanks.
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 07/10] Remove some of the kmemleak false positives
2006-07-11 6:49 ` Pekka Enberg
@ 2006-07-11 8:18 ` Catalin Marinas
0 siblings, 0 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-11 8:18 UTC (permalink / raw)
To: Pekka Enberg; +Cc: linux-kernel
On 11/07/06, Pekka Enberg <penberg@cs.helsinki.fi> wrote:
> On 7/11/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> > @@ -166,6 +166,9 @@ struct platform_device *platform_device_
> > struct platform_object *pa;
> >
> > pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL);
> > + /* kmemleak cannot guess the object type because the block
> > + * size is different from the object size */
> > + memleak_typeid(pa, struct platform_object);
>
> AFAICT, we about 300 kmalloc and kzalloc calls in the kernel that
> would need this annotation.
Most of them wouldn't need this annotation. The problem here is that
the stored pointer is usually pointing to &pa->pdev.dev and "pa" is
accessed via two container_of macros. There might be a few more cases
like this which I didn't find but I don't expect a large number.
> If we really can't fix the detector to deal with these,
As I posted a few weeks ago, this cannot be done without introducing a
lot of false negatives.
> I would prefer we introduce another memory allocator
> function such as:
>
> void *kzalloc_extra(size_t obj_size, size_t nr_extra, gfp_t flags);
>
> That would do the right thing for memleak too.
There is another case where extra bytes are added in front of the
structure for alignment (the function could have "before" and "after"
arguments). As I said above there aren't many places where kmemleak
needs this.
As Ingo said in the past, we could better go for precise type
identification/checking in kmalloc and both the kernel and kmemleak
would benefit from this (but that's a pretty large patch).
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-10 22:09 [PATCH 00/10] Kernel memory leak detector 0.8 Catalin Marinas
` (9 preceding siblings ...)
2006-07-10 22:11 ` [PATCH 10/10] Update the MAINTAINERS file " Catalin Marinas
@ 2006-07-11 12:27 ` Michal Piotrowski
2006-07-11 12:46 ` Michal Piotrowski
2006-07-11 12:56 ` Catalin Marinas
10 siblings, 2 replies; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-11 12:27 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
Hi Catalin,
On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> This is a new version (0.8) of the kernel memory leak detector. See
> the Documentation/kmemleak.txt file for a more detailed
> description. The patches are downloadable from (the whole patch or the
> broken-out series):
>
> http://homepage.ntlworld.com/cmarinas/kmemleak/patch-2.6.18-rc1-kmemleak-0.8.bz2
> http://homepage.ntlworld.com/cmarinas/kmemleak/patches-kmemleak-0.8.tar.bz2
>
Unfortunately, it doesn't compile for me.
make O=/dir
[..]
CC arch/i386/kernel/alternative.o
{standard input}: Assembler messages:
{standard input}:1954: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1955: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1959: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1960: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1964: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1965: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1972: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1973: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1979: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1980: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1984: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1985: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1989: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1990: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1997: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:1998: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:2004: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:2005: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:2009: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:2010: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:2014: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:2015: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:2022: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
{standard input}:2023: Error: can't resolve `.data' {.data section} -
`.Ltext0' {.text section}
make[2]: *** [arch/i386/kernel/alternative.o] Error 1
make[1]: *** [arch/i386/kernel] Error 2
make: *** [_all] Error 2
> --
> Catalin
> -
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 12:27 ` [PATCH 00/10] Kernel memory leak detector 0.8 Michal Piotrowski
@ 2006-07-11 12:46 ` Michal Piotrowski
2006-07-11 12:51 ` Michal Piotrowski
2006-07-11 12:56 ` Catalin Marinas
1 sibling, 1 reply; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-11 12:46 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> Hi Catalin,
>
> On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> > This is a new version (0.8) of the kernel memory leak detector. See
> > the Documentation/kmemleak.txt file for a more detailed
> > description. The patches are downloadable from (the whole patch or the
> > broken-out series):
> >
> > http://homepage.ntlworld.com/cmarinas/kmemleak/patch-2.6.18-rc1-kmemleak-0.8.bz2
> > http://homepage.ntlworld.com/cmarinas/kmemleak/patches-kmemleak-0.8.tar.bz2
> >
>
> Unfortunately, it doesn't compile for me.
>
> make O=/dir
> [..]
> CC arch/i386/kernel/alternative.o
[snip]
When I set DEBUG_KEEP_INIT=n everything works fine.
Here is the culprit 08-kmemleak-keep-init.patch
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 12:46 ` Michal Piotrowski
@ 2006-07-11 12:51 ` Michal Piotrowski
2006-07-11 13:00 ` Catalin Marinas
0 siblings, 1 reply; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-11 12:51 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > Hi Catalin,
> >
> > On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> > > This is a new version (0.8) of the kernel memory leak detector. See
> > > the Documentation/kmemleak.txt file for a more detailed
> > > description. The patches are downloadable from (the whole patch or the
> > > broken-out series):
> > >
> > > http://homepage.ntlworld.com/cmarinas/kmemleak/patch-2.6.18-rc1-kmemleak-0.8.bz2
> > > http://homepage.ntlworld.com/cmarinas/kmemleak/patches-kmemleak-0.8.tar.bz2
> > >
> >
> > Unfortunately, it doesn't compile for me.
> >
> > make O=/dir
> > [..]
> > CC arch/i386/kernel/alternative.o
> [snip]
>
> When I set DEBUG_KEEP_INIT=n everything works fine.
I was wrong. Here is the new error
/usr/src/linux-work4/kernel/pid.c: In function 'pid_task':
/usr/src/linux-work4/kernel/pid.c:262: error: initializer element is
not constant
/usr/src/linux-work4/kernel/pid.c:262: error: (near initialization for
'__memleak_offset__container_of.offset')
make[2]: *** [kernel/pid.o] Error 1
make[1]: *** [kernel] Error 2
make: *** [_all] Error 2
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 12:27 ` [PATCH 00/10] Kernel memory leak detector 0.8 Michal Piotrowski
2006-07-11 12:46 ` Michal Piotrowski
@ 2006-07-11 12:56 ` Catalin Marinas
2006-07-11 13:17 ` Michal Piotrowski
1 sibling, 1 reply; 49+ messages in thread
From: Catalin Marinas @ 2006-07-11 12:56 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: linux-kernel
On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> Unfortunately, it doesn't compile for me.
>
> make O=/dir
> [..]
> CC arch/i386/kernel/alternative.o
> {standard input}: Assembler messages:
> {standard input}:1954: Error: can't resolve `.data' {.data section} -
> `.Ltext0' {.text section}
I don't get any error (and kmemleak doesn't touch this file). Is this
with the 2.6.18-rc1 kernel?
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 12:51 ` Michal Piotrowski
@ 2006-07-11 13:00 ` Catalin Marinas
2006-07-11 13:09 ` Michal Piotrowski
2006-07-12 9:57 ` Joseph Fannin
0 siblings, 2 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-11 13:00 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: linux-kernel
On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > When I set DEBUG_KEEP_INIT=n everything works fine.
>
> I was wrong.
You mean the previous e-mail wasn't a kmemleak bug?
> Here is the new error
> /usr/src/linux-work4/kernel/pid.c: In function 'pid_task':
> /usr/src/linux-work4/kernel/pid.c:262: error: initializer element is
> not constant
> /usr/src/linux-work4/kernel/pid.c:262: error: (near initialization for
> '__memleak_offset__container_of.offset')
> make[2]: *** [kernel/pid.o] Error 1
> make[1]: *** [kernel] Error 2
> make: *** [_all] Error 2
That's a bug in gcc-4. The __builtin_constant_p() function always
returns true even when the argument is not a constant. You could try a
gcc-3.4 or a patched gcc.
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 13:00 ` Catalin Marinas
@ 2006-07-11 13:09 ` Michal Piotrowski
2006-07-12 9:57 ` Joseph Fannin
1 sibling, 0 replies; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-11 13:09 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > > When I set DEBUG_KEEP_INIT=n everything works fine.
> >
> > I was wrong.
>
> You mean the previous e-mail wasn't a kmemleak bug?
It is kmemleak bug. I wrote "I was wrog" concerning "everything works fine" :)
>
> > Here is the new error
> > /usr/src/linux-work4/kernel/pid.c: In function 'pid_task':
> > /usr/src/linux-work4/kernel/pid.c:262: error: initializer element is
> > not constant
> > /usr/src/linux-work4/kernel/pid.c:262: error: (near initialization for
> > '__memleak_offset__container_of.offset')
> > make[2]: *** [kernel/pid.o] Error 1
> > make[1]: *** [kernel] Error 2
> > make: *** [_all] Error 2
>
> That's a bug in gcc-4.
Yes of course. I forgot about this.
> The __builtin_constant_p() function always
> returns true even when the argument is not a constant. You could try a
> gcc-3.4 or a patched gcc.
>
> --
> Catalin
>
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 12:56 ` Catalin Marinas
@ 2006-07-11 13:17 ` Michal Piotrowski
2006-07-11 13:28 ` Catalin Marinas
0 siblings, 1 reply; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-11 13:17 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > Unfortunately, it doesn't compile for me.
> >
> > make O=/dir
> > [..]
> > CC arch/i386/kernel/alternative.o
> > {standard input}: Assembler messages:
> > {standard input}:1954: Error: can't resolve `.data' {.data section} -
> > `.Ltext0' {.text section}
>
> I don't get any error (and kmemleak doesn't touch this file). Is this
> with the 2.6.18-rc1 kernel?
It's a gcc 4.1 issue
gcc --version
gcc (GCC) 4.1.1 20060525 (Red Hat 4.1.1-1)
With gcc 3.4 it build.
>
> --
> Catalin
>
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 13:17 ` Michal Piotrowski
@ 2006-07-11 13:28 ` Catalin Marinas
2006-07-11 13:49 ` Michal Piotrowski
0 siblings, 1 reply; 49+ messages in thread
From: Catalin Marinas @ 2006-07-11 13:28 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: linux-kernel
On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> With gcc 3.4 it build.
Could you try with CONFIG_DEBUG_KEEP_INIT=y and gcc-3.4? It seems to
work OK for me. Maybe I miss something but just defining an empty
__init shouldn't cause problems.
Thanks.
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 13:28 ` Catalin Marinas
@ 2006-07-11 13:49 ` Michal Piotrowski
2006-07-11 14:02 ` Catalin Marinas
0 siblings, 1 reply; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-11 13:49 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > With gcc 3.4 it build.
>
> Could you try with CONFIG_DEBUG_KEEP_INIT=y and gcc-3.4? It seems to
> work OK for me.
It builds fine.
System hangs when I try "cat /sys/kernel/debug/memleak". Here is what
I found in a log file.
Jul 11 15:40:13 ltg01-fedora kernel: [<c0106e09>] show_trace_log_lvl+0x54/0xff
Jul 11 15:40:11 ltg01-fedora kernel: [<c0106ec1>] show_trace+0xd/0xf
Jul 11 15:40:12 ltg01-fedora kernel: [<c0106f93>] dump_stack+0x17/0x19
Jul 11 15:40:12 ltg01-fedora kernel: [<c017572c>] memleak_free+0x10e/0x183
Jul 11 15:40:13 ltg01-fedora kernel: [<c01734c2>] __cache_free+0x1e/0x5a
Jul 11 15:40:13 ltg01-fedora kernel: [<c0173a42>] kmem_cache_free+0x54/0x6e
Jul 11 15:40:11 ltg01-fedora kernel: [<c01205cd>] pgd_free+0xf/0x12
Jul 11 15:40:12 ltg01-fedora kernel: [<c0127254>] __mmdrop+0x1d/0x33
Jul 11 15:40:13 ltg01-fedora kernel: [<c02f1d32>] schedule+0x64a/0x6a9
Jul 11 15:40:14 ltg01-fedora kernel: [<fd962493>] evdev_read+0xe2/0x174 [evdev]
Jul 11 15:40:11 ltg01-fedora kernel: [<c0177fb7>] vfs_read+0xa9/0x151
Jul 11 15:40:12 ltg01-fedora kernel: [<c01782d7>] sys_read+0x3b/0x60
Jul 11 15:40:13 ltg01-fedora kernel: [<c0105ef1>] sysenter_past_esp+0x56/0x8d
Jul 11 15:40:13 ltg01-fedora kernel: [<b7ff8410>] 0xb7ff8410
Jul 11 15:40:13 ltg01-fedora kernel: kmemleak: pointer 0xf24ad000:
Jul 11 15:40:13 ltg01-fedora kernel: trace:
Jul 11 15:40:10 ltg01-fedora kernel: c01735c2: <kmem_cache_alloc>
Jul 11 15:40:11 ltg01-fedora kernel: c01205bc: <pgd_alloc>
Jul 11 15:40:12 ltg01-fedora kernel: c01271df: <mm_init>
Jul 11 15:40:12 ltg01-fedora kernel: c01273f1: <dup_mm>
Jul 11 15:40:11 ltg01-fedora kernel: c01276b5: <copy_mm>
Jul 11 15:40:11 ltg01-fedora kernel: c012853c: <copy_process>
Jul 11 15:40:12 ltg01-fedora kernel: c0128c46: <do_fork>
Jul 11 15:40:13 ltg01-fedora kernel: c0104cee: <sys_clone>
Jul 11 15:40:12 ltg01-fedora kernel: kmemleak: freeing orphan pointer 0xf24ad000
Jul 11 15:40:12 ltg01-fedora kernel: [<c0106e09>] show_trace_log_lvl+0x54/0xff
Jul 11 15:40:11 ltg01-fedora kernel: [<c0106ec1>] show_trace+0xd/0xf
Jul 11 15:40:13 ltg01-fedora kernel: [<c0106f93>] dump_stack+0x17/0x19
Jul 11 15:40:12 ltg01-fedora kernel: [<c017572c>] memleak_free+0x10e/0x183
Jul 11 15:40:11 ltg01-fedora kernel: [<c01734c2>] __cache_free+0x1e/0x5a
Jul 11 15:40:12 ltg01-fedora kernel: [<c0173a42>] kmem_cache_free+0x54/0x6e
Jul 11 15:40:13 ltg01-fedora kernel: [<c028f9d9>] uhci_free_urb_priv+0x7a/0x82
Jul 11 15:40:12 ltg01-fedora kernel: [<c0290803>] uhci_giveback_urb+0xb3/0x148
Jul 11 15:40:12 ltg01-fedora kernel: [<c029093a>] uhci_scan_qh+0xa2/0x18f
Jul 11 15:40:46 ltg01-fedora kernel: [<c0290b71>] uhci_scan_schedule+0x89/0x116
Jul 11 15:41:03 ltg01-fedora kernel: [<c02916ce>] uhci_irq+0x108/0x120
Jul 11 15:42:16 ltg01-fedora kernel: [<c0282568>] usb_hcd_irq+0x2a/0x53
Jul 11 15:42:29 ltg01-fedora kernel: [<c0156cd8>] handle_IRQ_event+0x1f/0x4c
Jul 11 15:42:51 ltg01-fedora kernel: [<c0156d92>] __do_IRQ+0x8d/0xe9
Jul 11 15:43:08 ltg01-fedora kernel: [<c01086ee>] do_IRQ+0xc2/0xd4
Jul 11 15:46:22 ltg01-fedora kernel: [<c010695d>] common_interrupt+0x25/0x2c
Jul 11 15:47:31 ltg01-fedora kernel: [<c012ed44>] __do_softirq+0x65/0xea
Jul 11 15:47:43 ltg01-fedora kernel: [<c01087f5>] do_softirq+0x60/0xc5
Jul 11 15:48:17 ltg01-fedora kernel: [<c012ee11>] irq_exit+0x48/0x55
Jul 11 15:49:09 ltg01-fedora kernel: [<c011a105>]
smp_apic_timer_interrupt+0x69/0x6c
http://www.stardust.webpages.pl/files/o_bugs/kml/kml-config4
> Thanks.
>
> --
> Catalin
>
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 13:49 ` Michal Piotrowski
@ 2006-07-11 14:02 ` Catalin Marinas
2006-07-11 15:02 ` Michal Piotrowski
0 siblings, 1 reply; 49+ messages in thread
From: Catalin Marinas @ 2006-07-11 14:02 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: linux-kernel
On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> System hangs when I try "cat /sys/kernel/debug/memleak". Here is what
> I found in a log file.
Can you disable DEBUG_MEMLEAK_ORPHAN_FREEING? That's mainly used for
debugging but I don't think it is was causing the hang. I haven't
changed the locking mechanism since version 0.7 but maybe some other
bug made its way in.
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 14:02 ` Catalin Marinas
@ 2006-07-11 15:02 ` Michal Piotrowski
2006-07-11 15:44 ` Catalin Marinas
2006-07-12 10:33 ` Catalin Marinas
0 siblings, 2 replies; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-11 15:02 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > System hangs when I try "cat /sys/kernel/debug/memleak". Here is what
> > I found in a log file.
>
> Can you disable DEBUG_MEMLEAK_ORPHAN_FREEING? That's mainly used for
> debugging but I don't think it is was causing the hang. I haven't
> changed the locking mechanism since version 0.7 but maybe some other
> bug made its way in.
It is DEBUG_MEMLEAK_ORPHAN_FREEING issue. Disabling it solved the problem.
orphan pointer 0xc6113bec (size 28):
c017392a: <__kmalloc_track_caller>
c01631b1: <__kzalloc>
c010b7d7: <legacy_init_iomem_resources>
c010b89c: <request_standard_resources>
c0100b8b: <do_initcalls>
c0100c3d: <do_basic_setup>
c0100cdb: <init>
This is most common
orphan pointer 0xf5a6fd60 (size 39):
c0173822: <__kmalloc>
c01df500: <context_struct_to_string>
c01df679: <security_sid_to_context>
c01d7eee: <selinux_socket_getpeersec_dgram>
f884f019: <unix_get_peersec_dgram>
f8850698: <unix_dgram_sendmsg>
c02a88c2: <sock_sendmsg>
c02a9c7a: <sys_sendto>
cat /tmp/ml.txt | grep -c selinux_socket_getpeersec_dgram
8442
>
> --
> Catalin
>
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 15:02 ` Michal Piotrowski
@ 2006-07-11 15:44 ` Catalin Marinas
2006-07-11 16:02 ` Michal Piotrowski
2006-07-12 10:33 ` Catalin Marinas
1 sibling, 1 reply; 49+ messages in thread
From: Catalin Marinas @ 2006-07-11 15:44 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: linux-kernel
On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> It is DEBUG_MEMLEAK_ORPHAN_FREEING issue. Disabling it solved the
> problem.
OK, thanks for trying.
> orphan pointer 0xc6113bec (size 28):
> c017392a: <__kmalloc_track_caller>
> c01631b1: <__kzalloc>
> c010b7d7: <legacy_init_iomem_resources>
> c010b89c: <request_standard_resources>
> c0100b8b: <do_initcalls>
> c0100c3d: <do_basic_setup>
> c0100cdb: <init>
That's a real leak. I posted a patch last night that solves this issue
- http://lkml.org/lkml/2006/7/10/370
> This is most common
> orphan pointer 0xf5a6fd60 (size 39):
> c0173822: <__kmalloc>
> c01df500: <context_struct_to_string>
> c01df679: <security_sid_to_context>
> c01d7eee: <selinux_socket_getpeersec_dgram>
> f884f019: <unix_get_peersec_dgram>
> f8850698: <unix_dgram_sendmsg>
> c02a88c2: <sock_sendmsg>
> c02a9c7a: <sys_sendto>
Looking at the call trace, the pointer to the memory allocated in
context_struct_to_string() is stored in the "cb" variable in struct
sk_buff (argument passed to selinux_socket_getpeersec_dgram from
unix_get_peersec_dgram).
This pointer should be found when scanning the "struct sk_buff"
blocks, unless you also get a comparable number of "struct sk_buff"
reports (from __alloc_skb). If not, it might be a real leak.
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 15:44 ` Catalin Marinas
@ 2006-07-11 16:02 ` Michal Piotrowski
2006-07-11 16:31 ` Catalin Marinas
0 siblings, 1 reply; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-11 16:02 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> > orphan pointer 0xc6113bec (size 28):
> > c017392a: <__kmalloc_track_caller>
> > c01631b1: <__kzalloc>
> > c010b7d7: <legacy_init_iomem_resources>
> > c010b89c: <request_standard_resources>
> > c0100b8b: <do_initcalls>
> > c0100c3d: <do_basic_setup>
> > c0100cdb: <init>
>
> That's a real leak. I posted a patch last night that solves this issue
> - http://lkml.org/lkml/2006/7/10/370
Thanks.
>
> > This is most common
> > orphan pointer 0xf5a6fd60 (size 39):
> > c0173822: <__kmalloc>
> > c01df500: <context_struct_to_string>
> > c01df679: <security_sid_to_context>
> > c01d7eee: <selinux_socket_getpeersec_dgram>
> > f884f019: <unix_get_peersec_dgram>
> > f8850698: <unix_dgram_sendmsg>
> > c02a88c2: <sock_sendmsg>
> > c02a9c7a: <sys_sendto>
>
> Looking at the call trace, the pointer to the memory allocated in
> context_struct_to_string() is stored in the "cb" variable in struct
> sk_buff (argument passed to selinux_socket_getpeersec_dgram from
> unix_get_peersec_dgram).
>
> This pointer should be found when scanning the "struct sk_buff"
> blocks, unless you also get a comparable number of "struct sk_buff"
> reports (from __alloc_skb). If not, it might be a real leak.
So if we got 3970
orphan pointer 0xf5a6fd60 (size 39):
c0173822: <__kmalloc>
c01df500: <context_struct_to_string>
c01df679: <security_sid_to_context>
c01d7eee: <selinux_socket_getpeersec_dgram>
f884f019: <unix_get_peersec_dgram>
f8850698: <unix_dgram_sendmsg>
c02a88c2: <sock_sendmsg>
c02a9c7a: <sys_sendto>
and 4673
orphan pointer 0xf4249488 (size 29):
c0173822: <__kmalloc>
c01df500: <context_struct_to_string>
c01df679: <security_sid_to_context>
c01d7eee: <selinux_socket_getpeersec_dgram>
f884f019: <unix_get_peersec_dgram>
f8850698: <unix_dgram_sendmsg>
c02a8d68: <do_sock_write>
c02a8e85: <sock_aio_write>
It's not a memleak?
http://www.stardust.webpages.pl/files/o_bugs/kml/ml3.txt
>
> --
> Catalin
>
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 16:02 ` Michal Piotrowski
@ 2006-07-11 16:31 ` Catalin Marinas
2006-07-11 17:00 ` Michal Piotrowski
0 siblings, 1 reply; 49+ messages in thread
From: Catalin Marinas @ 2006-07-11 16:31 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1173 bytes --]
On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> > Looking at the call trace, the pointer to the memory allocated in
> > context_struct_to_string() is stored in the "cb" variable in struct
> > sk_buff (argument passed to selinux_socket_getpeersec_dgram from
> > unix_get_peersec_dgram).
> >
> > This pointer should be found when scanning the "struct sk_buff"
> > blocks, unless you also get a comparable number of "struct sk_buff"
> > reports (from __alloc_skb). If not, it might be a real leak.
>
> So if we got 3970
> orphan pointer 0xf5a6fd60 (size 39):
> c0173822: <__kmalloc>
> c01df500: <context_struct_to_string>
[...]
> and 4673
> orphan pointer 0xf4249488 (size 29):
> c0173822: <__kmalloc>
> c01df500: <context_struct_to_string>
[...]
> It's not a memleak?
Not exactly. What I meant is that if you have a corresponding number
of reports from __alloc_skb, maybe they were false positives and the
block wasn't scanned leading to other false positive reports
It looks like there are some reports in __alloc_skb. Please try the
attached patch.
Thanks.
--
Catalin
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: alloc_skb-false-positive.patch --]
[-- Type: text/x-patch; name="alloc_skb-false-positive.patch", Size: 849 bytes --]
Clear the false positive in __alloc_skb
From: Catalin Marinas <catalin.marinas@arm.com>
This happens when fclone is 1 because the allocated size is different from
the struct sk_buff one and therefore the pointer aliases are not correctly
determined.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
net/core/skbuff.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 44f6a18..ee4fd9b 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -158,6 +158,9 @@ struct sk_buff *__alloc_skb(unsigned int
/* Get the HEAD */
skb = kmem_cache_alloc(cache, gfp_mask & ~__GFP_DMA);
+ /* the skbuff_fclone_cache contains objects larger than
+ * "struct sk_buff" and kmemleak cannot guess the type */
+ memleak_typeid(skb, struct sk_buff);
if (!skb)
goto out;
^ permalink raw reply related [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 16:31 ` Catalin Marinas
@ 2006-07-11 17:00 ` Michal Piotrowski
2006-07-11 21:54 ` Catalin Marinas
0 siblings, 1 reply; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-11 17:00 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > So if we got 3970
> > orphan pointer 0xf5a6fd60 (size 39):
> > c0173822: <__kmalloc>
> > c01df500: <context_struct_to_string>
> [...]
> > and 4673
> > orphan pointer 0xf4249488 (size 29):
> > c0173822: <__kmalloc>
> > c01df500: <context_struct_to_string>
> [...]
> > It's not a memleak?
>
> Not exactly. What I meant is that if you have a corresponding number
> of reports from __alloc_skb, maybe they were false positives and the
> block wasn't scanned leading to other false positive reports
>
> It looks like there are some reports in __alloc_skb. Please try the
> attached patch.
Here is the result
http://www.stardust.webpages.pl/files/o_bugs/kml/ml4.txt
>
> Thanks.
>
> --
> Catalin
>
>
>
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 17:00 ` Michal Piotrowski
@ 2006-07-11 21:54 ` Catalin Marinas
2006-07-12 11:35 ` Michal Piotrowski
2006-07-12 13:19 ` Michal Piotrowski
0 siblings, 2 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-11 21:54 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: linux-kernel
Michal,
On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> > It looks like there are some reports in __alloc_skb. Please try the
> > attached patch.
>
> Here is the result
> http://www.stardust.webpages.pl/files/o_bugs/kml/ml4.txt
Some of the __alloc_skb disappeared but there are still a lot of
context_struct_to_string (812). Could you let it running for a bit to
get more reported leaks (few thousands) and send me the contents of
the /proc/slabinfo file (together with the memleak file)? I want to
make sure whether it is a kmemleak problem or not.
Thanks.
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 13:00 ` Catalin Marinas
2006-07-11 13:09 ` Michal Piotrowski
@ 2006-07-12 9:57 ` Joseph Fannin
2006-07-12 10:38 ` Catalin Marinas
1 sibling, 1 reply; 49+ messages in thread
From: Joseph Fannin @ 2006-07-12 9:57 UTC (permalink / raw)
To: Catalin Marinas; +Cc: Michal Piotrowski, linux-kernel
On Tue, Jul 11, 2006 at 02:00:05PM +0100, Catalin Marinas wrote:
> On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> >On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> >> When I set DEBUG_KEEP_INIT=n everything works fine.
> >
> >I was wrong.
>
> You mean the previous e-mail wasn't a kmemleak bug?
>
> >Here is the new error
> >/usr/src/linux-work4/kernel/pid.c: In function 'pid_task':
> >/usr/src/linux-work4/kernel/pid.c:262: error: initializer element is
> >not constant
> >/usr/src/linux-work4/kernel/pid.c:262: error: (near initialization for
> >'__memleak_offset__container_of.offset')
> >make[2]: *** [kernel/pid.o] Error 1
> >make[1]: *** [kernel] Error 2
> >make: *** [_all] Error 2
>
> That's a bug in gcc-4. The __builtin_constant_p() function always
> returns true even when the argument is not a constant. You could try a
> gcc-3.4 or a patched gcc.
Which gcc versions are affected by this?
--
Joseph Fannin
jhf@rivenstone.net
"Bull in pure form is rare; there is usually some contamination by data."
-- William Graves Perry Jr.
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 15:02 ` Michal Piotrowski
2006-07-11 15:44 ` Catalin Marinas
@ 2006-07-12 10:33 ` Catalin Marinas
2006-07-12 18:46 ` Xiaolan Zhang
2006-07-13 18:52 ` Xiaolan Zhang
1 sibling, 2 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-12 10:33 UTC (permalink / raw)
To: Catherine Zhang; +Cc: Michal Piotrowski, linux-kernel
Hi Catherine,
On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> This is most common
> orphan pointer 0xf5a6fd60 (size 39):
> c0173822: <__kmalloc>
> c01df500: <context_struct_to_string>
> c01df679: <security_sid_to_context>
> c01d7eee: <selinux_socket_getpeersec_dgram>
> f884f019: <unix_get_peersec_dgram>
> f8850698: <unix_dgram_sendmsg>
> c02a88c2: <sock_sendmsg>
> c02a9c7a: <sys_sendto>
>
> cat /tmp/ml.txt | grep -c selinux_socket_getpeersec_dgram
> 8442
I'm looking into the above leak report from kmemleak (the back trace
to the kmalloc function). The "datagram getpeersec" patch went in as
commit 877ce7c1b3afd69a9b1caeb1b9964c992641f52a. Have you noticed any
abnormal increase in the slab statistics (especially size-64)?
Thanks.
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-12 9:57 ` Joseph Fannin
@ 2006-07-12 10:38 ` Catalin Marinas
2006-07-12 10:49 ` Michal Piotrowski
2006-07-14 2:22 ` Horst von Brand
0 siblings, 2 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-12 10:38 UTC (permalink / raw)
To: Michal Piotrowski, linux-kernel
On 12/07/06, Joseph Fannin <jfannin@gmail.com> wrote:
> On Tue, Jul 11, 2006 at 02:00:05PM +0100, Catalin Marinas wrote:
> > That's a bug in gcc-4. The __builtin_constant_p() function always
> > returns true even when the argument is not a constant. You could try a
> > gcc-3.4 or a patched gcc.
>
> Which gcc versions are affected by this?
>From gcc-4.0 I think but I don't know when/if it was fixed in the
latest. I use CodeSourcery's toolchain and they fixed in in gcc-4.1
but that's with their own patches. Try to compile the code below. It
should work if the toolchain is OK:
#include <stdlib.h>
#define EXPR atoi(argv[1])
int main(int argc, char *argv[])
{
static int a[] = {
__builtin_constant_p(EXPR) ? EXPR : 0
};
return a[0];
}
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-12 10:38 ` Catalin Marinas
@ 2006-07-12 10:49 ` Michal Piotrowski
2006-07-14 2:22 ` Horst von Brand
1 sibling, 0 replies; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-12 10:49 UTC (permalink / raw)
To: Catalin Marinas; +Cc: Joseph Fannin, linux-kernel
On 12/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> On 12/07/06, Joseph Fannin <jfannin@gmail.com> wrote:
> > On Tue, Jul 11, 2006 at 02:00:05PM +0100, Catalin Marinas wrote:
> > > That's a bug in gcc-4. The __builtin_constant_p() function always
> > > returns true even when the argument is not a constant. You could try a
> > > gcc-3.4 or a patched gcc.
> >
> > Which gcc versions are affected by this?
>
> From gcc-4.0 I think but I don't know when/if it was fixed in the
> latest.
gcc-4.2 --version
gcc-4.2 (GCC) 4.2.0 20060701 (experimental)
works fine for me.
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 21:54 ` Catalin Marinas
@ 2006-07-12 11:35 ` Michal Piotrowski
2006-07-12 16:17 ` Catalin Marinas
2006-07-12 13:19 ` Michal Piotrowski
1 sibling, 1 reply; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-12 11:35 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
Hi Catalin,
On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> Michal,
>
> On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> > > It looks like there are some reports in __alloc_skb. Please try the
> > > attached patch.
> >
> > Here is the result
> > http://www.stardust.webpages.pl/files/o_bugs/kml/ml4.txt
>
> Some of the __alloc_skb disappeared but there are still a lot of
> context_struct_to_string (812). Could you let it running for a bit to
> get more reported leaks (few thousands) and send me the contents of
> the /proc/slabinfo file (together with the memleak file)? I want to
> make sure whether it is a kmemleak problem or not.
Ok.
BTW I have _very_ annoying soft lockup. Can you fix that?
Jul 12 13:15:47 ltg01-fedora kernel: printk: 1527 messages suppressed.
Jul 12 13:15:47 ltg01-fedora kernel: ipt_hook: happy cracking.
Jul 12 13:15:56 ltg01-fedora kernel: printk: 1631 messages suppressed.
Jul 12 13:15:56 ltg01-fedora kernel: Neighbour table overflow.
I don't know why, but clock goes mad.
Jul 12 14:08:21 ltg01-fedora kernel: BUG: soft lockup detected on CPU#0!
Jul 12 14:08:19 ltg01-fedora kernel: [<c0106e09>] show_trace_log_lvl+0x54/0xff
Jul 12 14:08:20 ltg01-fedora kernel: [<c0106ec1>] show_trace+0xd/0xf
Jul 12 14:08:19 ltg01-fedora kernel: [<c0106f93>] dump_stack+0x17/0x19
Jul 12 14:08:21 ltg01-fedora kernel: [<c0156793>] softlockup_tick+0x9a/0xae
Jul 12 14:08:21 ltg01-fedora kernel: [<c01332ce>] run_local_timers+0x12/0x14
Jul 12 14:08:21 ltg01-fedora kernel: [<c0133126>]
update_process_times+0x40/0x65
Jul 12 14:08:20 ltg01-fedora kernel: [<c011a100>]
smp_apic_timer_interrupt+0x64/0x6c
Jul 12 14:08:21 ltg01-fedora kernel: [<c0106a1e>]
apic_timer_interrupt+0x2a/0x30
Jul 12 14:08:18 ltg01-fedora kernel: [<c0116b71>] smp_call_function+0xcc/0xf9
Jul 12 14:08:20 ltg01-fedora kernel: [<c012f6b6>] on_each_cpu+0x24/0x5e
Jul 12 14:08:21 ltg01-fedora kernel: [<c017a63f>] invalidate_bh_lrus+0x16/0x18
Jul 12 14:08:21 ltg01-fedora kernel: [<c017978c>] invalidate_bdev+0xb/0x1c
Jul 12 14:08:19 ltg01-fedora smartd[1736]: Device: /dev/hda, 1 Offline
uncorrectable sectors
Jul 12 14:08:21 ltg01-fedora kernel: [<c017e81d>] kill_bdev+0x10/0x25
Jul 12 14:08:20 ltg01-fedora kernel: [<c017fa7f>] __blkdev_put+0x43/0x157
Jul 12 14:08:21 ltg01-fedora kernel: [<c017fb9d>] blkdev_put+0xa/0xc
Jul 12 14:08:20 ltg01-fedora kernel: [<c017fbd6>] blkdev_close+0x28/0x2b
Jul 12 14:08:20 ltg01-fedora kernel: [<c0178e20>] __fput+0xb2/0x18c
Jul 12 14:08:20 ltg01-fedora kernel: [<c0178d6c>] fput+0x17/0x19
Jul 12 14:08:20 ltg01-fedora kernel: [<c01778c5>] filp_close+0x4e/0x58
Jul 12 14:08:22 ltg01-fedora kernel: [<c0177931>] sys_close+0x62/0x7a
Jul 12 14:08:21 ltg01-fedora kernel: [<c0105ef1>] sysenter_past_esp+0x56/0x8d
Jul 12 14:08:22 ltg01-fedora kernel: [<b7fc1410>] 0xb7fc1410
Jul 12 14:08:22 ltg01-fedora kernel: BUG: soft lockup detected on CPU#1!
Jul 12 14:08:21 ltg01-fedora kernel: [<c0106e09>] show_trace_log_lvl+0x54/0xff
Jul 12 14:08:21 ltg01-fedora kernel: [<c0106ec1>] show_trace+0xd/0xf
Jul 12 14:08:21 ltg01-fedora kernel: [<c0106f93>] dump_stack+0x17/0x19
Jul 12 14:08:21 ltg01-fedora kernel: [<c0156793>] softlockup_tick+0x9a/0xae
Jul 12 14:08:20 ltg01-fedora kernel: [<c01332ce>] run_local_timers+0x12/0x14
Jul 12 14:08:20 ltg01-fedora kernel: [<c0133126>]
update_process_times+0x40/0x65
Jul 12 14:08:20 ltg01-fedora kernel: [<c011a100>]
smp_apic_timer_interrupt+0x64/0x6c
Jul 12 14:08:22 ltg01-fedora kernel: [<c0106a1e>]
apic_timer_interrupt+0x2a/0x30
Jul 12 14:08:20 ltg01-fedora kernel: [<c02f3dd1>] _spin_unlock_irq+0x28/0x43
Jul 12 14:08:20 ltg01-fedora kernel: [<c012dcb2>] do_setitimer+0x145/0x4ce
Jul 12 14:08:20 ltg01-fedora kernel: [<c012e070>] alarm_setitimer+0x35/0x54
Jul 12 14:08:22 ltg01-fedora kernel: [<c0133371>] sys_alarm+0xb/0xd
Jul 12 14:08:21 ltg01-fedora kernel: [<c0105ef1>] sysenter_past_esp+0x56/0x8d
Jul 12 14:08:21 ltg01-fedora kernel: [<b7f83410>] 0xb7f83410
Jul 12 14:08:21 ltg01-fedora kernel: printk: 309 messages suppressed.
Jul 12 14:08:22 ltg01-fedora kernel: ipt_hook: happy cracking.
Here is actual config file
http://www.stardust.webpages.pl/files/o_bugs/kml/kml-config5
>
> Thanks.
>
> --
> Catalin
>
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-11 21:54 ` Catalin Marinas
2006-07-12 11:35 ` Michal Piotrowski
@ 2006-07-12 13:19 ` Michal Piotrowski
2006-07-12 14:37 ` Catalin Marinas
1 sibling, 1 reply; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-12 13:19 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> Michal,
>
> On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > On 11/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> > > It looks like there are some reports in __alloc_skb. Please try the
> > > attached patch.
> >
> > Here is the result
> > http://www.stardust.webpages.pl/files/o_bugs/kml/ml4.txt
>
> Some of the __alloc_skb disappeared but there are still a lot of
> context_struct_to_string (812). Could you let it running for a bit to
> get more reported leaks (few thousands) and send me the contents of
> the /proc/slabinfo file (together with the memleak file)? I want to
> make sure whether it is a kmemleak problem or not.
Here is a slabinfo from current 2.6.18-rc1-git4 and 2.6.18-rc1 +
kmemleak http://www.stardust.webpages.pl/files/o_bugs/kml/slab.txt
I haven't seen that before
orphan pointer 0xf1283e34 (size 224):
c01735c2: <kmem_cache_alloc>
fdc8c5cf: <ip_conntrack_alloc>
fdc8c6a3: <init_conntrack>
fdc8c894: <ip_conntrack_in>
fdc8b652: <ip_conntrack_local>
c02c15bf: <nf_iterate>
c02c1630: <nf_hook_slow>
c02e127e: <raw_send_hdrinc>
http://www.stardust.webpages.pl/files/o_bugs/kml/ml5.txt (4MB)
>
> Thanks.
>
> --
> Catalin
>
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-12 13:19 ` Michal Piotrowski
@ 2006-07-12 14:37 ` Catalin Marinas
2006-07-12 15:33 ` Michal Piotrowski
0 siblings, 1 reply; 49+ messages in thread
From: Catalin Marinas @ 2006-07-12 14:37 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: linux-kernel
On 12/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> Here is a slabinfo from current 2.6.18-rc1-git4 and 2.6.18-rc1 +
> kmemleak http://www.stardust.webpages.pl/files/o_bugs/kml/slab.txt
Thanks. Does it make any difference if you enable
CONFIG_DEBUG_MEMLEAK_TASK_STACKS? Also, if you save the memleak file
periodically, do any of the context_struct_to_string reports disappear
(I can investigate this if you upload a few ml60.txt, mk61.txt etc.)?
> I haven't seen that before
> orphan pointer 0xf1283e34 (size 224):
> c01735c2: <kmem_cache_alloc>
> fdc8c5cf: <ip_conntrack_alloc>
> fdc8c6a3: <init_conntrack>
> fdc8c894: <ip_conntrack_in>
> fdc8b652: <ip_conntrack_local>
> c02c15bf: <nf_iterate>
> c02c1630: <nf_hook_slow>
> c02e127e: <raw_send_hdrinc>
This looks like a false positive as the conntrack pointer is lost in
init_conntrack and only a pointer conntrack->tuplehash[...].list is
stored. This cannot be aliased via container_of because
tuplehash_to_ctrack doesn't pass a constant argument to it and cannot
be determined at compile time. Try the attached patch.
Note that you can get some false positives that might disappear after
a while. This is because of the stacks scanning and also pointers
stored in CPU registers, especially on SMP systems.
Thanks.
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-12 14:37 ` Catalin Marinas
@ 2006-07-12 15:33 ` Michal Piotrowski
2006-07-12 16:12 ` Catalin Marinas
0 siblings, 1 reply; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-12 15:33 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
On 12/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> On 12/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > Here is a slabinfo from current 2.6.18-rc1-git4 and 2.6.18-rc1 +
> > kmemleak http://www.stardust.webpages.pl/files/o_bugs/kml/slab.txt
>
> Thanks. Does it make any difference if you enable
> CONFIG_DEBUG_MEMLEAK_TASK_STACKS? Also, if you save the memleak file
> periodically, do any of the context_struct_to_string reports disappear
> (I can investigate this if you upload a few ml60.txt, mk61.txt etc.)?
Here are the results
http://www.stardust.webpages.pl/files/o_bugs/kml/ml/
>
> --
> Catalin
>
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-12 15:33 ` Michal Piotrowski
@ 2006-07-12 16:12 ` Catalin Marinas
0 siblings, 0 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-12 16:12 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: linux-kernel
On 12/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> On 12/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> > On 12/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > > Here is a slabinfo from current 2.6.18-rc1-git4 and 2.6.18-rc1 +
> > > kmemleak http://www.stardust.webpages.pl/files/o_bugs/kml/slab.txt
> >
> > Thanks. Does it make any difference if you enable
> > CONFIG_DEBUG_MEMLEAK_TASK_STACKS? Also, if you save the memleak file
> > periodically, do any of the context_struct_to_string reports disappear
> > (I can investigate this if you upload a few ml60.txt, mk61.txt etc.)?
>
> Here are the results
> http://www.stardust.webpages.pl/files/o_bugs/kml/ml/
The context_struct_to_string leaks do not seem to disappear in
subsequent ml?.txt files which makes me think it's a real leak.
Thanks for collecting these statistics.
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-12 11:35 ` Michal Piotrowski
@ 2006-07-12 16:17 ` Catalin Marinas
2006-07-12 22:55 ` Michal Piotrowski
0 siblings, 1 reply; 49+ messages in thread
From: Catalin Marinas @ 2006-07-12 16:17 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: linux-kernel
On 12/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> BTW I have _very_ annoying soft lockup. Can you fix that?
>
> Jul 12 13:15:47 ltg01-fedora kernel: printk: 1527 messages suppressed.
> Jul 12 13:15:47 ltg01-fedora kernel: ipt_hook: happy cracking.
> Jul 12 13:15:56 ltg01-fedora kernel: printk: 1631 messages suppressed.
> Jul 12 13:15:56 ltg01-fedora kernel: Neighbour table overflow.
>
> I don't know why, but clock goes mad.
>
> Jul 12 14:08:21 ltg01-fedora kernel: BUG: soft lockup detected on CPU#0!
Maybe the soft lockup report is cause by the clock change (it doesn't
show any kmemleak functions in the backtrace). You could change
SCAN_BLOCK_SIZE in memleak.c to a smaller value as the scanning is
done with the interrupt disabled.
I'll try tomorrow on my platforms with the soft lockup enabled.
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-12 10:33 ` Catalin Marinas
@ 2006-07-12 18:46 ` Xiaolan Zhang
2006-07-13 18:52 ` Xiaolan Zhang
1 sibling, 0 replies; 49+ messages in thread
From: Xiaolan Zhang @ 2006-07-12 18:46 UTC (permalink / raw)
To: Catalin Marinas; +Cc: Catherine Zhang, linux-kernel, Michal Piotrowski
Catalin,
I am looking into this problem.
thanks,
Catherine
"Catalin Marinas" <catalin.marinas@gmail.com> wrote on 07/12/2006 06:33:54
AM:
> Hi Catherine,
>
> On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > This is most common
> > orphan pointer 0xf5a6fd60 (size 39):
> > c0173822: <__kmalloc>
> > c01df500: <context_struct_to_string>
> > c01df679: <security_sid_to_context>
> > c01d7eee: <selinux_socket_getpeersec_dgram>
> > f884f019: <unix_get_peersec_dgram>
> > f8850698: <unix_dgram_sendmsg>
> > c02a88c2: <sock_sendmsg>
> > c02a9c7a: <sys_sendto>
> >
> > cat /tmp/ml.txt | grep -c selinux_socket_getpeersec_dgram
> > 8442
>
> I'm looking into the above leak report from kmemleak (the back trace
> to the kmalloc function). The "datagram getpeersec" patch went in as
> commit 877ce7c1b3afd69a9b1caeb1b9964c992641f52a. Have you noticed any
> abnormal increase in the slab statistics (especially size-64)?
>
> Thanks.
>
> --
> Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-12 16:17 ` Catalin Marinas
@ 2006-07-12 22:55 ` Michal Piotrowski
2006-07-13 16:35 ` Catalin Marinas
0 siblings, 1 reply; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-12 22:55 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
On 12/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> On 12/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > BTW I have _very_ annoying soft lockup. Can you fix that?
> >
> > Jul 12 13:15:47 ltg01-fedora kernel: printk: 1527 messages suppressed.
> > Jul 12 13:15:47 ltg01-fedora kernel: ipt_hook: happy cracking.
> > Jul 12 13:15:56 ltg01-fedora kernel: printk: 1631 messages suppressed.
> > Jul 12 13:15:56 ltg01-fedora kernel: Neighbour table overflow.
> >
> > I don't know why, but clock goes mad.
> >
> > Jul 12 14:08:21 ltg01-fedora kernel: BUG: soft lockup detected on CPU#0!
>
> Maybe the soft lockup report is cause by the clock change (it doesn't
> show any kmemleak functions in the backtrace).
I can't reproduce this on clean 2.6.18-rc1.
> You could change
> SCAN_BLOCK_SIZE in memleak.c to a smaller value as the scanning is
> done with the interrupt disabled.
I have tried
#define SCAN_BLOCK_SIZE 2048
and
#define SCAN_BLOCK_SIZE 1024
Unfortunately it doesn't change anything.
> I'll try tomorrow on my platforms with the soft lockup enabled.
Please try something like this
on tty1
isic -s rand -d your ip (http://www.packetfactory.net/Projects/ISIC/)
on tty2
kml_collector (http://www.stardust.webpages.pl/files/o_bugs/kml/ml/kml_collector.sh)
(I have tried to read random files from /sys on vanilla kernel, but I
can't reproduce that lockup)
>
> --
> Catalin
>
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-12 22:55 ` Michal Piotrowski
@ 2006-07-13 16:35 ` Catalin Marinas
2006-07-13 19:14 ` Michal Piotrowski
0 siblings, 1 reply; 49+ messages in thread
From: Catalin Marinas @ 2006-07-13 16:35 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1062 bytes --]
On 12/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> I have tried
> #define SCAN_BLOCK_SIZE 2048
> and
> #define SCAN_BLOCK_SIZE 1024
> Unfortunately it doesn't change anything.
I realised that this only reduces the time running with interrupts
disabled but won't solve the soft lockup.
> Please try something like this
> on tty1
> isic -s rand -d your ip (http://www.packetfactory.net/Projects/ISIC/)
> on tty2
> kml_collector (http://www.stardust.webpages.pl/files/o_bugs/kml/ml/kml_collector.sh)
>
> (I have tried to read random files from /sys on vanilla kernel, but I
> can't reproduce that lockup)
Couldn't get it on my (embedded) platform but I think that's because
there are only a few reports in the memleak file. You have thousands
of reports and I think reading the memleak file is causing the soft
lockup.
Until we identify the leak (or false positive), you can use the
attached patch to supress the reports for context_struct_to_string.
Hopefully, this should eliminate the soft lockup as well.
--
Catalin
[-- Attachment #2: context_struct_to_string-not-leak.patch --]
[-- Type: text/x-patch, Size: 959 bytes --]
Ignore the (real) leak report in context_struct_to_string
From: Catalin Marinas <catalin.marinas@arm.com>
This might be a real leak but, because of the amount of information
kmemleak reports, we ignore it for now to allow testing of other parts of
kmemleak.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
security/selinux/ss/services.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index d2e80e6..f8cf098 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -548,6 +548,9 @@ static int context_struct_to_string(stru
/* Allocate space for the context; caller must free this space. */
scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
+ /* This might be a real leak but we ignore it for now to allow
+ * testing other parts of kmemleak */
+ memleak_not_leak(scontextp);
if (!scontextp) {
return -ENOMEM;
}
^ permalink raw reply related [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-12 10:33 ` Catalin Marinas
2006-07-12 18:46 ` Xiaolan Zhang
@ 2006-07-13 18:52 ` Xiaolan Zhang
2006-07-13 19:17 ` Michal Piotrowski
1 sibling, 1 reply; 49+ messages in thread
From: Xiaolan Zhang @ 2006-07-13 18:52 UTC (permalink / raw)
To: Catalin Marinas; +Cc: Catherine Zhang, linux-kernel, Michal Piotrowski
Hi, Catalin,
I have identified the problem and will submit a fix soon. Could you let
me know to which tree should I apply the fix against?
thanks,
Catherine
"Catalin Marinas" <catalin.marinas@gmail.com> wrote on 07/12/2006 06:33:54
AM:
> Hi Catherine,
>
> On 11/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > This is most common
> > orphan pointer 0xf5a6fd60 (size 39):
> > c0173822: <__kmalloc>
> > c01df500: <context_struct_to_string>
> > c01df679: <security_sid_to_context>
> > c01d7eee: <selinux_socket_getpeersec_dgram>
> > f884f019: <unix_get_peersec_dgram>
> > f8850698: <unix_dgram_sendmsg>
> > c02a88c2: <sock_sendmsg>
> > c02a9c7a: <sys_sendto>
> >
> > cat /tmp/ml.txt | grep -c selinux_socket_getpeersec_dgram
> > 8442
>
> I'm looking into the above leak report from kmemleak (the back trace
> to the kmalloc function). The "datagram getpeersec" patch went in as
> commit 877ce7c1b3afd69a9b1caeb1b9964c992641f52a. Have you noticed any
> abnormal increase in the slab statistics (especially size-64)?
>
> Thanks.
>
> --
> Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-13 16:35 ` Catalin Marinas
@ 2006-07-13 19:14 ` Michal Piotrowski
2006-07-14 14:53 ` Catalin Marinas
0 siblings, 1 reply; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-13 19:14 UTC (permalink / raw)
To: Catalin Marinas; +Cc: linux-kernel
Hi Catalin,
On 13/07/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> On 12/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> > Please try something like this
> > on tty1
> > isic -s rand -d your ip (http://www.packetfactory.net/Projects/ISIC/)
> > on tty2
> > kml_collector (http://www.stardust.webpages.pl/files/o_bugs/kml/ml/kml_collector.sh)
> >
> > (I have tried to read random files from /sys on vanilla kernel, but I
> > can't reproduce that lockup)
>
> Couldn't get it on my (embedded) platform but I think that's because
> there are only a few reports in the memleak file. You have thousands
> of reports and I think reading the memleak file is causing the soft
> lockup.
>
> Until we identify the leak (or false positive), you can use the
> attached patch to supress the reports for context_struct_to_string.
> Hopefully, this should eliminate the soft lockup as well.
Thanks.
After applying context_struct_to_string-not-leak.patch and reverting
alloc_skb-false-positive.patch I haven't noticed that soft lockup.
Here is something new
orphan pointer 0xf40d61ac (size 1536):
c017392a: <__kmalloc_track_caller>
c01631b1: <__kzalloc>
f98869cd: <skge_ring_alloc>
f9888a1d: <skge_up>
c02b17b6: <dev_open>
c02b2e94: <dev_change_flags>
c02e6e17: <devinet_ioctl>
c02e8a02: <inet_ioctl>
http://www.stardust.webpages.pl/files/o_bugs/kml/ml2/
http://www.stardust.webpages.pl/files/o_bugs/kml/ml3/
After alloc_skb-false-positive.patch revert
http://www.stardust.webpages.pl/files/o_bugs/kml/ml4/
>
> --
> Catalin
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-13 18:52 ` Xiaolan Zhang
@ 2006-07-13 19:17 ` Michal Piotrowski
0 siblings, 0 replies; 49+ messages in thread
From: Michal Piotrowski @ 2006-07-13 19:17 UTC (permalink / raw)
To: Xiaolan Zhang; +Cc: Catalin Marinas, Catherine Zhang, linux-kernel
Hi Catherine,
On 13/07/06, Xiaolan Zhang <cxzhang@us.ibm.com> wrote:
> Hi, Catalin,
>
> I have identified the problem and will submit a fix soon.
Great, thanks!
> Could you let
> me know to which tree should I apply the fix against?
2.6.18-rc1.
>
> thanks,
> Catherine
>
Regards,
Michal
--
Michal K. K. Piotrowski
LTG - Linux Testers Group
(http://www.stardust.webpages.pl/ltg/wiki/)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-12 10:38 ` Catalin Marinas
2006-07-12 10:49 ` Michal Piotrowski
@ 2006-07-14 2:22 ` Horst von Brand
1 sibling, 0 replies; 49+ messages in thread
From: Horst von Brand @ 2006-07-14 2:22 UTC (permalink / raw)
To: Catalin Marinas; +Cc: Michal Piotrowski, linux-kernel
Catalin Marinas <catalin.marinas@gmail.com> wrote:
> On 12/07/06, Joseph Fannin <jfannin@gmail.com> wrote:
> > On Tue, Jul 11, 2006 at 02:00:05PM +0100, Catalin Marinas wrote:
> > > That's a bug in gcc-4. The __builtin_constant_p() function always
> > > returns true even when the argument is not a constant. You could try a
> > > gcc-3.4 or a patched gcc.
> >
> > Which gcc versions are affected by this?
>
> From gcc-4.0 I think but I don't know when/if it was fixed in the
> latest. I use CodeSourcery's toolchain and they fixed in in gcc-4.1
> but that's with their own patches. Try to compile the code below. It
> should work if the toolchain is OK:
>
> #include <stdlib.h>
>
> #define EXPR atoi(argv[1])
>
> int main(int argc, char *argv[])
> {
> static int a[] = {
> __builtin_constant_p(EXPR) ? EXPR : 0
> };
>
> return a[0];
> }
Fails with gcc-4.1.1-7 from Fedora Core development.
--
Dr. Horst H. von Brand User #22616 counter.li.org
Departamento de Informatica Fono: +56 32 654431
Universidad Tecnica Federico Santa Maria +56 32 654239
Casilla 110-V, Valparaiso, Chile Fax: +56 32 797513
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH 00/10] Kernel memory leak detector 0.8
2006-07-13 19:14 ` Michal Piotrowski
@ 2006-07-14 14:53 ` Catalin Marinas
0 siblings, 0 replies; 49+ messages in thread
From: Catalin Marinas @ 2006-07-14 14:53 UTC (permalink / raw)
To: Michal Piotrowski; +Cc: linux-kernel
On 13/07/06, Michal Piotrowski <michal.k.k.piotrowski@gmail.com> wrote:
> After applying context_struct_to_string-not-leak.patch and reverting
> alloc_skb-false-positive.patch I haven't noticed that soft lockup.
You still need the apply alloc_skb-false-positive.patch as it just
avoids a false positive (I'll add it to kmemleak 0.9). Does anything
change with this (and the context_struct_... one)?
> Here is something new
> orphan pointer 0xf40d61ac (size 1536):
> c017392a: <__kmalloc_track_caller>
> c01631b1: <__kzalloc>
> f98869cd: <skge_ring_alloc>
> f9888a1d: <skge_up>
> c02b17b6: <dev_open>
> c02b2e94: <dev_change_flags>
> c02e6e17: <devinet_ioctl>
> c02e8a02: <inet_ioctl>
This looks like a leak but I couldn't find anything obvious with the
code. I'll keep looking.
> http://www.stardust.webpages.pl/files/o_bugs/kml/ml2/
> http://www.stardust.webpages.pl/files/o_bugs/kml/ml3/
I would also need to investigate why the report shows some orphan
pointers without any back-trace information. It seems to disappear
after a while.
Thanks.
--
Catalin
^ permalink raw reply [flat|nested] 49+ messages in thread
end of thread, other threads:[~2006-07-14 14:53 UTC | newest]
Thread overview: 49+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-07-10 22:09 [PATCH 00/10] Kernel memory leak detector 0.8 Catalin Marinas
2006-07-10 22:09 ` [PATCH 01/10] Base support for kmemleak Catalin Marinas
2006-07-10 22:09 ` [PATCH 02/10] Some documentation " Catalin Marinas
2006-07-10 22:09 ` [PATCH 03/10] Add the memory allocation/freeing hooks " Catalin Marinas
2006-07-11 6:17 ` Pekka Enberg
2006-07-11 7:59 ` Catalin Marinas
2006-07-10 22:10 ` [PATCH 04/10] Modules support " Catalin Marinas
2006-07-10 22:10 ` [PATCH 05/10] Add kmemleak support for i386 Catalin Marinas
2006-07-10 22:10 ` [PATCH 06/10] Add kmemleak support for ARM Catalin Marinas
2006-07-10 22:10 ` [PATCH 07/10] Remove some of the kmemleak false positives Catalin Marinas
2006-07-11 6:49 ` Pekka Enberg
2006-07-11 8:18 ` Catalin Marinas
2006-07-10 22:10 ` [PATCH 08/10] Keep the __init functions after initialization Catalin Marinas
2006-07-10 22:10 ` [PATCH 09/10] Simple testing for kmemleak Catalin Marinas
2006-07-10 22:11 ` [PATCH 10/10] Update the MAINTAINERS file " Catalin Marinas
2006-07-11 12:27 ` [PATCH 00/10] Kernel memory leak detector 0.8 Michal Piotrowski
2006-07-11 12:46 ` Michal Piotrowski
2006-07-11 12:51 ` Michal Piotrowski
2006-07-11 13:00 ` Catalin Marinas
2006-07-11 13:09 ` Michal Piotrowski
2006-07-12 9:57 ` Joseph Fannin
2006-07-12 10:38 ` Catalin Marinas
2006-07-12 10:49 ` Michal Piotrowski
2006-07-14 2:22 ` Horst von Brand
2006-07-11 12:56 ` Catalin Marinas
2006-07-11 13:17 ` Michal Piotrowski
2006-07-11 13:28 ` Catalin Marinas
2006-07-11 13:49 ` Michal Piotrowski
2006-07-11 14:02 ` Catalin Marinas
2006-07-11 15:02 ` Michal Piotrowski
2006-07-11 15:44 ` Catalin Marinas
2006-07-11 16:02 ` Michal Piotrowski
2006-07-11 16:31 ` Catalin Marinas
2006-07-11 17:00 ` Michal Piotrowski
2006-07-11 21:54 ` Catalin Marinas
2006-07-12 11:35 ` Michal Piotrowski
2006-07-12 16:17 ` Catalin Marinas
2006-07-12 22:55 ` Michal Piotrowski
2006-07-13 16:35 ` Catalin Marinas
2006-07-13 19:14 ` Michal Piotrowski
2006-07-14 14:53 ` Catalin Marinas
2006-07-12 13:19 ` Michal Piotrowski
2006-07-12 14:37 ` Catalin Marinas
2006-07-12 15:33 ` Michal Piotrowski
2006-07-12 16:12 ` Catalin Marinas
2006-07-12 10:33 ` Catalin Marinas
2006-07-12 18:46 ` Xiaolan Zhang
2006-07-13 18:52 ` Xiaolan Zhang
2006-07-13 19:17 ` Michal Piotrowski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox