diff --git a/btrfs-progs-valgrind.patch b/btrfs-progs-valgrind.patch
new file mode 100644
index 0000000..3adbe57
--- /dev/null
+++ b/btrfs-progs-valgrind.patch
@@ -0,0 +1,247 @@
+Hello,
+
+Started running valgrind against btrfsck since e2fsck seemed to have a myriad of
+problems.  btrfsck was actually not in too bad shape, only like 5 or 6 normal
+errors and maybe 5 leaks.  The big leak is the "seen" extent cache that we don't
+seem to do anything with.  Since I'm not sure what Yan is up to I just made it
+so we free that cache before we return in case he wants it for something.  With
+these changes btrfsck doesn't spit out any errors while running valgrind and has
+no leaks.  This should also help any of the other utilities that use the generic
+stuff.  Thanks,
+
+Signed-off-by: Josef Bacik <jbacik@redhat.com>
+---
+ btrfsck.c      |    2 ++
+ disk-io.c      |   29 ++++++++++++++++++-----------
+ extent-cache.c |   11 +++++++++++
+ extent-cache.h |    1 +
+ extent-tree.c  |   10 ++++++++++
+ extent_io.c    |    1 +
+ volumes.c      |   16 +++++++++++++++-
+ volumes.h      |    1 +
+ 8 files changed, 59 insertions(+), 12 deletions(-)
+
+diff --git a/btrfsck.c b/btrfsck.c
+index 40c90f8..9dd777f 100644
+--- a/btrfsck.c
++++ b/btrfsck.c
+@@ -2431,6 +2431,8 @@ static int check_extents(struct btrfs_root *root)
+ 			break;
+ 	}
+ 	ret = check_extent_refs(root, &extent_cache);
++	free_cache_tree(&seen);
++	free(bits);
+ 	return ret;
+ }
+ 
+diff --git a/disk-io.c b/disk-io.c
+index addebe1..4d4e902 100644
+--- a/disk-io.c
++++ b/disk-io.c
+@@ -425,8 +425,10 @@ static int find_and_setup_log_root(struct btrfs_root *tree_root,
+ 	u64 blocknr = btrfs_super_log_root(disk_super);
+ 	struct btrfs_root *log_root = malloc(sizeof(struct btrfs_root));
+ 
+-	if (blocknr == 0)
++	if (blocknr == 0) {
++		free(log_root);
+ 		return 0;
++	}
+ 
+ 	blocksize = btrfs_level_size(tree_root,
+ 			     btrfs_super_log_root_level(disk_super));
+@@ -605,7 +607,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
+ 	struct btrfs_root *chunk_root = malloc(sizeof(struct btrfs_root));
+ 	struct btrfs_root *dev_root = malloc(sizeof(struct btrfs_root));
+ 	struct btrfs_root *csum_root = malloc(sizeof(struct btrfs_root));
+-	struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info));
++	struct btrfs_fs_info *fs_info = malloc(sizeof(struct btrfs_fs_info));
+ 	int ret;
+ 	struct btrfs_super_block *disk_super;
+ 	struct btrfs_fs_devices *fs_devices = NULL;
+@@ -628,7 +630,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
+ 		BUG_ON(ret);
+ 	}
+ 
+-	memset(fs_info, 0, sizeof(*fs_info));
++	memset(fs_info, 0, sizeof(struct btrfs_fs_info));
+ 	fs_info->tree_root = tree_root;
+ 	fs_info->extent_root = extent_root;
+ 	fs_info->chunk_root = chunk_root;
+@@ -928,15 +930,19 @@ static int close_all_devices(struct btrfs_fs_info *fs_info)
+ {
+ 	struct list_head *list;
+ 	struct list_head *next;
++	struct list_head *tmp;
+ 	struct btrfs_device *device;
+ 
+-	return 0;
+-
+ 	list = &fs_info->fs_devices->devices;
+-	list_for_each(next, list) {
++	list_for_each_safe(next, tmp, list) {
+ 		device = list_entry(next, struct btrfs_device, dev_list);
+ 		close(device->fd);
++		list_del(&device->dev_list);
++		free(device->name);
++		free(device->label);
++		free(device);
+ 	}
++	free(fs_info->fs_devices);
+ 	return 0;
+ }
+ 
+@@ -970,25 +976,26 @@ int close_ctree(struct btrfs_root *root)
+ 	if (fs_info->csum_root->node)
+ 		free_extent_buffer(fs_info->csum_root->node);
+ 
+-	if (root->fs_info->log_root_tree) {
+-		if (root->fs_info->log_root_tree->node)
+-			free_extent_buffer(root->fs_info->log_root_tree->node);
+-		free(root->fs_info->log_root_tree);
++	if (fs_info->log_root_tree) {
++		if (fs_info->log_root_tree->node)
++			free_extent_buffer(fs_info->log_root_tree->node);
+ 	}
+ 
+-	close_all_devices(root->fs_info);
++	close_all_devices(fs_info);
+ 	extent_io_tree_cleanup(&fs_info->extent_cache);
+ 	extent_io_tree_cleanup(&fs_info->free_space_cache);
+ 	extent_io_tree_cleanup(&fs_info->block_group_cache);
+ 	extent_io_tree_cleanup(&fs_info->pinned_extents);
+ 	extent_io_tree_cleanup(&fs_info->pending_del);
+ 	extent_io_tree_cleanup(&fs_info->extent_ins);
++	btrfs_mapping_tree_free(&fs_info->mapping_tree);
+ 
+ 	free(fs_info->tree_root);
+ 	free(fs_info->extent_root);
+ 	free(fs_info->chunk_root);
+ 	free(fs_info->dev_root);
+ 	free(fs_info->csum_root);
++	free(fs_info->log_root_tree);
+ 	free(fs_info);
+ 
+ 	return 0;
+diff --git a/extent-cache.c b/extent-cache.c
+index b871e18..b424975 100644
+--- a/extent-cache.c
++++ b/extent-cache.c
+@@ -170,3 +170,14 @@ void remove_cache_extent(struct cache_tree *tree,
+ 	rb_erase(&pe->rb_node, &tree->root);
+ }
+ 
++void free_cache_tree(struct cache_tree *tree)
++{
++	struct rb_node *node;
++	struct cache_extent *cache;
++
++	while ((node = rb_last(&tree->root)) != NULL) {
++		cache = rb_entry(node, struct cache_extent, rb_node);
++		remove_cache_extent(tree, cache);
++		free(cache);
++	}
++}
+diff --git a/extent-cache.h b/extent-cache.h
+index 7f2f2a6..1696bc2 100644
+--- a/extent-cache.h
++++ b/extent-cache.h
+@@ -43,6 +43,7 @@ struct cache_extent *find_cache_extent(struct cache_tree *tree,
+ int insert_cache_extent(struct cache_tree *tree, u64 start, u64 size);
+ int insert_existing_cache_extent(struct cache_tree *tree,
+ 				 struct cache_extent *pe);
++void free_cache_tree(struct cache_tree *tree);
+ 
+ static inline int cache_tree_empty(struct cache_tree *tree)
+ {
+diff --git a/extent-tree.c b/extent-tree.c
+index b2f9bb2..e1d7ffd 100644
+--- a/extent-tree.c
++++ b/extent-tree.c
+@@ -2985,6 +2985,7 @@ out:
+ 
+ int btrfs_free_block_groups(struct btrfs_fs_info *info)
+ {
++	struct btrfs_space_info *space_info;
+ 	u64 start;
+ 	u64 end;
+ 	u64 ptr;
+@@ -3008,6 +3009,15 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
+ 		clear_extent_dirty(&info->free_space_cache, start,
+ 				   end, GFP_NOFS);
+ 	}
++
++	while (!list_empty(&info->space_info)) {
++		space_info = list_entry(info->space_info.next,
++					struct btrfs_space_info,
++					list);
++		list_del(&space_info->list);
++		kfree(space_info);
++	}
++
+ 	return 0;
+ }
+ 
+diff --git a/extent_io.c b/extent_io.c
+index 069c199..71e6826 100644
+--- a/extent_io.c
++++ b/extent_io.c
+@@ -572,6 +572,7 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
+ 		BUG();
+ 		return NULL;
+ 	}
++	memset(eb, 0, sizeof(struct extent_buffer) + blocksize);
+ 
+ 	eb->start = bytenr;
+ 	eb->len = blocksize;
+diff --git a/volumes.c b/volumes.c
+index 7671855..eee66a7 100644
+--- a/volumes.c
++++ b/volumes.c
+@@ -862,6 +862,20 @@ void btrfs_mapping_init(struct btrfs_mapping_tree *tree)
+ 	cache_tree_init(&tree->cache_tree);
+ }
+ 
++void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree)
++{
++	struct cache_extent *cache;
++	struct rb_node *node;
++	struct map_lookup *map;
++
++	while ((node = rb_last(&tree->cache_tree.root)) != NULL) {
++		cache = rb_entry(node, struct cache_extent, rb_node);
++		map = container_of(cache, struct map_lookup, ce);
++		remove_cache_extent(&tree->cache_tree, cache);
++		free(map);
++	}
++}
++
+ int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len)
+ {
+ 	struct cache_extent *ce;
+@@ -1340,7 +1354,7 @@ int btrfs_read_sys_array(struct btrfs_root *root)
+ 	if (!sb)
+ 		return -ENOMEM;
+ 	btrfs_set_buffer_uptodate(sb);
+-	write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE);
++	write_extent_buffer(sb, super_copy, 0, sizeof(*super_copy));
+ 	array_size = btrfs_super_sys_array_size(super_copy);
+ 
+ 	/*
+diff --git a/volumes.h b/volumes.h
+index bb78751..e466b31 100644
+--- a/volumes.h
++++ b/volumes.h
+@@ -130,4 +130,5 @@ int btrfs_add_system_chunk(struct btrfs_trans_handle *trans,
+ 			   struct btrfs_root *root, struct btrfs_key *key,
+ 			   struct btrfs_chunk *chunk, int item_size);
+ int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
++void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree);
+ #endif
+-- 
+1.5.4.3
+
+--
+To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff --git a/btrfs-progs.spec b/btrfs-progs.spec
index 7122fed..381cd25 100644
--- a/btrfs-progs.spec
+++ b/btrfs-progs.spec
@@ -1,6 +1,6 @@
 Name:           btrfs-progs
 Version:        0.19
-Release:        6%{?dist}
+Release:        7%{?dist}
 Summary:        Userspace programs for btrfs
 
 Group:          System Environment/Base
@@ -9,6 +9,7 @@ URL:            http://btrfs.wiki.kernel.org/index.php/Main_Page
 Source0:        http://www.kernel.org/pub/linux/kernel/people/mason/btrfs/%{name}-%{version}.tar.bz2
 Patch0: btrfs-progs-fix-labels.patch
 Patch1: btrfs-progs-build-everything.patch
+Patch2: btrfs-progs-valgrind.patch
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
 BuildRequires:  e2fsprogs-devel, libuuid-devel, zlib-devel, libacl-devel
@@ -23,6 +24,7 @@ check, modify and correct any inconsistencies in the btrfs filesystem.
 %setup -q
 %patch0 -p1
 %patch1 -p1
+%patch2 -p1
 
 %build
 make CFLAGS="$RPM_OPT_FLAGS" %{?_smp_mflags}
@@ -54,6 +56,9 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man8/mkfs.btrfs.8.gz
 
 %changelog
+* Tue Aug 25 2009 Josef Bacik <josef@toxicpanda.com> 0.19-7
+- add btrfs-progs-valgrind.patch to fix memory leaks and segfaults
+
 * Fri Jul 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.19-6
 - Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild