From d828b9a4d7a0105f2222126d878714f74e1fc78b Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Fri, 10 Apr 2009 09:56:58 +0000 Subject: [PATCH] Helper function to catch memory pool leaks. --- WHATS_NEW | 1 + libdm/ioctl/libdm-iface.c | 3 +++ libdm/mm/pool-debug.c | 6 ++++++ libdm/mm/pool-fast.c | 3 +++ libdm/mm/pool.c | 23 +++++++++++++++++++++++ 5 files changed, 36 insertions(+) diff --git a/WHATS_NEW b/WHATS_NEW index 373a7279f..c6ae2676d 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.46 - ================================ + Add memory pool leaks detection. Use copy of PV structure when manipulating with global PV lists. Always return exit error status when locking of volume group fails. Fix mirror log convert validation question. diff --git a/libdm/ioctl/libdm-iface.c b/libdm/ioctl/libdm-iface.c index fe864946b..3698edab6 100644 --- a/libdm/ioctl/libdm-iface.c +++ b/libdm/ioctl/libdm-iface.c @@ -1817,12 +1817,15 @@ void dm_lib_release(void) update_devs(); } +void dm_pools_check_leaks(void); + void dm_lib_exit(void) { dm_lib_release(); if (_dm_bitset) dm_bitset_destroy(_dm_bitset); _dm_bitset = NULL; + dm_pools_check_leaks(); dm_dump_memory(); _version_ok = 1; _version_checked = 0; diff --git a/libdm/mm/pool-debug.c b/libdm/mm/pool-debug.c index 1c3d999b8..f775dea6c 100644 --- a/libdm/mm/pool-debug.c +++ b/libdm/mm/pool-debug.c @@ -30,7 +30,9 @@ typedef struct { } pool_stats; struct dm_pool { + struct dm_list list; const char *name; + void *orig_pool; /* to pair it with first allocation call */ int begun; struct block *object; @@ -65,10 +67,13 @@ struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint) mem->stats.bytes = 0; mem->stats.maxbytes = 0; + mem->orig_pool = mem; + #ifdef DEBUG_POOL log_debug("Created mempool %s", name); #endif + dm_list_add(&_dm_pools, &mem->list); return mem; } @@ -103,6 +108,7 @@ void dm_pool_destroy(struct dm_pool *p) { _pool_stats(p, "Destroying"); _free_blocks(p, p->blocks); + dm_list_del(&p->list); dm_free(p); } diff --git a/libdm/mm/pool-fast.c b/libdm/mm/pool-fast.c index 9d9f80838..d34cd9aa6 100644 --- a/libdm/mm/pool-fast.c +++ b/libdm/mm/pool-fast.c @@ -21,6 +21,7 @@ struct chunk { }; struct dm_pool { + struct dm_list list; struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free list to stop 'bobbling' */ size_t chunk_size; @@ -51,6 +52,7 @@ struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint) while (new_size < p->chunk_size) new_size <<= 1; p->chunk_size = new_size; + dm_list_add(&_dm_pools, &p->list); return p; } @@ -65,6 +67,7 @@ void dm_pool_destroy(struct dm_pool *p) c = pr; } + dm_list_del(&p->list); dm_free(p); } diff --git a/libdm/mm/pool.c b/libdm/mm/pool.c index 3528a9119..35bfffae4 100644 --- a/libdm/mm/pool.c +++ b/libdm/mm/pool.c @@ -15,6 +15,10 @@ #include "dmlib.h" +/* FIXME: thread unsafe */ +static DM_LIST_INIT(_dm_pools); +void dm_pools_check_leaks(void); + #ifdef DEBUG_POOL #include "pool-debug.c" #else @@ -52,3 +56,22 @@ void *dm_pool_zalloc(struct dm_pool *p, size_t s) return ptr; } + +void dm_pools_check_leaks(void) +{ + struct dm_pool *p; + + if (dm_list_empty(&_dm_pools)) + return; + + log_error("You have a memory leak (not released memory pool):"); + dm_list_iterate_items(p, &_dm_pools) { +#ifdef DEBUG_POOL + log_error(" [%p] %s (%u bytes)", + p->orig_pool, + p->name, p->stats.bytes); +#else + log_error(" [%p]", p); +#endif + } +}