diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-03-26 20:24:23 (GMT) |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 15:04:01 (GMT) |
commit | 2d2ae547979854d10b75d557b3abdb3eb7511bbc (patch) | |
tree | 9a3bab510a9fadb2b8be27497041675ad0108938 /fs/btrfs | |
parent | 83041add611056e830e29fda913029e37e857239 (diff) | |
download | linux-fsl-qoriq-2d2ae547979854d10b75d557b3abdb3eb7511bbc.tar.xz |
Btrfs: Add leak debugging for extent_buffer and extent_state
This also fixes one leak around the super block when failing to mount the
FS.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/disk-io.c | 2 | ||||
-rw-r--r-- | fs/btrfs/extent_io.c | 28 | ||||
-rw-r--r-- | fs/btrfs/extent_io.h | 3 |
3 files changed, 30 insertions, 3 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 134b722..1c5e097 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -915,12 +915,14 @@ fail_tree_root: free_extent_buffer(tree_root->node); fail_sb_buffer: free_extent_buffer(fs_info->sb_buffer); + extent_io_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->io_tree); fail_iput: iput(fs_info->btree_inode); fail: close_all_devices(fs_info); kfree(extent_root); kfree(tree_root); + bdi_destroy(&fs_info->bdi); kfree(fs_info); return ERR_PTR(err); } diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 6dab664..b99cfab 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -26,6 +26,7 @@ static struct kmem_cache *extent_buffer_cache; static LIST_HEAD(buffers); static LIST_HEAD(states); +static spinlock_t leak_lock = SPIN_LOCK_UNLOCKED; #define BUFFER_LRU_MAX 64 @@ -64,15 +65,22 @@ free_state_cache: void extent_io_exit(void) { struct extent_state *state; + struct extent_buffer *eb; while (!list_empty(&states)) { - state = list_entry(states.next, struct extent_state, list); + state = list_entry(states.next, struct extent_state, leak_list); printk("state leak: start %Lu end %Lu state %lu in tree %p refs %d\n", state->start, state->end, state->state, state->tree, atomic_read(&state->refs)); - list_del(&state->list); + list_del(&state->leak_list); kmem_cache_free(extent_state_cache, state); } + while (!list_empty(&buffers)) { + eb = list_entry(buffers.next, struct extent_buffer, leak_list); + printk("buffer leak start %Lu len %lu refs %d\n", eb->start, eb->len, atomic_read(&eb->refs)); + list_del(&eb->leak_list); + kmem_cache_free(extent_buffer_cache, eb); + } if (extent_state_cache) kmem_cache_destroy(extent_state_cache); if (extent_buffer_cache) @@ -109,6 +117,7 @@ EXPORT_SYMBOL(extent_io_tree_empty_lru); struct extent_state *alloc_extent_state(gfp_t mask) { struct extent_state *state; + unsigned long flags; state = kmem_cache_alloc(extent_state_cache, mask); if (!state || IS_ERR(state)) @@ -116,6 +125,9 @@ struct extent_state *alloc_extent_state(gfp_t mask) state->state = 0; state->private = 0; state->tree = NULL; + spin_lock_irqsave(&leak_lock, flags); + list_add(&state->leak_list, &states); + spin_unlock_irqrestore(&leak_lock, flags); atomic_set(&state->refs, 1); init_waitqueue_head(&state->wq); @@ -128,7 +140,11 @@ void free_extent_state(struct extent_state *state) if (!state) return; if (atomic_dec_and_test(&state->refs)) { + unsigned long flags; WARN_ON(state->tree); + spin_lock_irqsave(&leak_lock, flags); + list_del(&state->leak_list); + spin_unlock_irqrestore(&leak_lock, flags); kmem_cache_free(extent_state_cache, state); } } @@ -2582,6 +2598,7 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree, gfp_t mask) { struct extent_buffer *eb = NULL; + unsigned long flags; spin_lock(&tree->lru_lock); eb = find_lru(tree, start, len); @@ -2594,6 +2611,9 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree, INIT_LIST_HEAD(&eb->lru); eb->start = start; eb->len = len; + spin_lock_irqsave(&leak_lock, flags); + list_add(&eb->leak_list, &buffers); + spin_unlock_irqrestore(&leak_lock, flags); atomic_set(&eb->refs, 1); return eb; @@ -2601,6 +2621,10 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree, static void __free_extent_buffer(struct extent_buffer *eb) { + unsigned long flags; + spin_lock_irqsave(&leak_lock, flags); + list_del(&eb->leak_list); + spin_unlock_irqrestore(&leak_lock, flags); kmem_cache_free(extent_buffer_cache, eb); } diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 8b5319d..16d67a6 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -66,7 +66,7 @@ struct extent_state { /* for use by the FS */ u64 private; - struct list_head list; + struct list_head leak_list; }; struct extent_buffer { @@ -80,6 +80,7 @@ struct extent_buffer { struct list_head lru; atomic_t refs; int flags; + struct list_head leak_list; }; struct extent_map_tree; |