aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Sandeen <sandeen@redhat.com>2018-03-08 20:35:22 -0600
committerEric Sandeen <sandeen@redhat.com>2018-03-08 20:35:22 -0600
commit444884913bd52a843eb49a757e6e65681ab2e90b (patch)
treef943a2fcb303b1c01d2d45017918032c04b03a0f
parentbf0e024fb10d623e8da98a0c41625a2007437a6a (diff)
downloadxfsprogs-dev-444884913bd52a843eb49a757e6e65681ab2e90b.tar.gz
libxfs: Catch non-empty zones on destroy
Create and use a kmem_zone_destroy which warns if we are releasing a non-empty zone when the LIBXFS_LEAK_CHECK environment variable is set, wire this into libxfs_destroy(), and call that when various tools exit. The LIBXFS_LEAK_CHECK environment variable also causes the program to exit with failure when a leak is detected, useful for failing automated tests if leaks are encountered. Signed-off-by: Eric Sandeen <sandeen@redhat.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
-rw-r--r--include/kmem.h1
-rw-r--r--libxfs/init.c36
-rw-r--r--libxfs/kmem.c14
3 files changed, 38 insertions, 13 deletions
diff --git a/include/kmem.h b/include/kmem.h
index 65f0aded6c..572a4fafac 100644
--- a/include/kmem.h
+++ b/include/kmem.h
@@ -33,6 +33,7 @@ typedef struct kmem_zone {
extern kmem_zone_t *kmem_zone_init(int, char *);
extern void *kmem_zone_alloc(kmem_zone_t *, int);
extern void *kmem_zone_zalloc(kmem_zone_t *, int);
+extern int kmem_zone_destroy(kmem_zone_t *);
static inline void
kmem_zone_free(kmem_zone_t *zone, void *ptr)
diff --git a/libxfs/init.c b/libxfs/init.c
index 3456cb519e..a65c86c341 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -43,7 +43,7 @@ int libxfs_bhash_size; /* #buckets in bcache */
int use_xfs_buf_lock; /* global flag: use xfs_buf_t locks for MT */
-static void manage_zones(int); /* setup global zones */
+static int manage_zones(int); /* setup/teardown global zones */
/*
* dev_map - map open devices to fd.
@@ -372,7 +372,7 @@ done:
/*
* Initialize/destroy all of the zone allocators we use.
*/
-static void
+static int
manage_zones(int release)
{
extern kmem_zone_t *xfs_buf_zone;
@@ -388,16 +388,20 @@ manage_zones(int release)
extern void xfs_dir_startup();
if (release) { /* free zone allocation */
- kmem_free(xfs_buf_zone);
- kmem_free(xfs_inode_zone);
- kmem_free(xfs_ifork_zone);
- kmem_free(xfs_buf_item_zone);
- kmem_free(xfs_da_state_zone);
- kmem_free(xfs_btree_cur_zone);
- kmem_free(xfs_bmap_free_item_zone);
- kmem_free(xfs_trans_zone);
- kmem_free(xfs_log_item_desc_zone);
- return;
+ int leaked = 0;
+
+ leaked += kmem_zone_destroy(xfs_buf_zone);
+ leaked += kmem_zone_destroy(xfs_ili_zone);
+ leaked += kmem_zone_destroy(xfs_inode_zone);
+ leaked += kmem_zone_destroy(xfs_ifork_zone);
+ leaked += kmem_zone_destroy(xfs_buf_item_zone);
+ leaked += kmem_zone_destroy(xfs_da_state_zone);
+ leaked += kmem_zone_destroy(xfs_btree_cur_zone);
+ leaked += kmem_zone_destroy(xfs_bmap_free_item_zone);
+ leaked += kmem_zone_destroy(xfs_trans_zone);
+ leaked += kmem_zone_destroy(xfs_log_item_desc_zone);
+
+ return leaked;
}
/* otherwise initialise zone allocation */
xfs_buf_zone = kmem_zone_init(sizeof(xfs_buf_t), "xfs_buffer");
@@ -419,6 +423,8 @@ manage_zones(int release)
xfs_log_item_desc_zone = kmem_zone_init(
sizeof(struct xfs_log_item_desc), "xfs_log_item_desc");
xfs_dir_startup();
+
+ return 0;
}
/*
@@ -887,11 +893,15 @@ libxfs_umount(xfs_mount_t *mp)
void
libxfs_destroy(void)
{
+ int leaked;
+
/* Free everything from the buffer cache before freeing buffer zone */
libxfs_bcache_purge();
libxfs_bcache_free();
cache_destroy(libxfs_bcache);
- manage_zones(1);
+ leaked = manage_zones(1);
+ if (getenv("LIBXFS_LEAK_CHECK") && leaked)
+ exit(1);
}
int
diff --git a/libxfs/kmem.c b/libxfs/kmem.c
index c8bcb50861..256db94f9e 100644
--- a/libxfs/kmem.c
+++ b/libxfs/kmem.c
@@ -23,6 +23,20 @@ kmem_zone_init(int size, char *name)
return ptr;
}
+int
+kmem_zone_destroy(kmem_zone_t *zone)
+{
+ int leaked = 0;
+
+ if (getenv("LIBXFS_LEAK_CHECK") && zone->allocated) {
+ leaked = 1;
+ fprintf(stderr, "zone %s freed with %d items allocated\n",
+ zone->zone_name, zone->allocated);
+ }
+ free(zone);
+ return leaked;
+}
+
void *
kmem_zone_alloc(kmem_zone_t *zone, int flags)
{