@@ -1217,7 +1217,11 @@ struct btrfs_fs_info {
/* the log root tree is a directory of all the other log roots */
struct btrfs_root *log_root_tree;
- struct extent_io_tree extent_cache;
+ struct cache_tree extent_cache;
+ u64 max_cache_size;
+ u64 cache_size;
+ struct list_head lru;
+
struct extent_io_tree dirty_buffers;
struct extent_io_tree free_space_cache;
struct extent_io_tree pinned_extents;
@@ -864,7 +864,7 @@ struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr)
!fs_info->block_group_root || !fs_info->super_copy)
goto free_all;
- extent_io_tree_init(&fs_info->extent_cache);
+ extent_buffer_init_cache(fs_info);
extent_io_tree_init(&fs_info->dirty_buffers);
extent_io_tree_init(&fs_info->free_space_cache);
extent_io_tree_init(&fs_info->pinned_extents);
@@ -1350,7 +1350,7 @@ void btrfs_cleanup_all_caches(struct btrfs_fs_info *fs_info)
}
free_mapping_cache_tree(&fs_info->mapping_tree.cache_tree);
extent_io_tree_cleanup(&fs_info->dirty_buffers);
- extent_io_tree_cleanup(&fs_info->extent_cache);
+ extent_buffer_free_cache(fs_info);
extent_io_tree_cleanup(&fs_info->free_space_cache);
extent_io_tree_cleanup(&fs_info->pinned_extents);
extent_io_tree_cleanup(&fs_info->extent_ins);
@@ -34,13 +34,45 @@
#include "common/device-utils.h"
#include "common/internal.h"
+static void free_extent_buffer_final(struct extent_buffer *eb);
+
+void extent_buffer_init_cache(struct btrfs_fs_info *fs_info)
+{
+ fs_info->max_cache_size = total_memory() / 4;
+ fs_info->cache_size = 0;
+ INIT_LIST_HEAD(&fs_info->lru);
+}
+
+void extent_buffer_free_cache(struct btrfs_fs_info *fs_info)
+{
+ struct extent_buffer *eb;
+
+ while(!list_empty(&fs_info->lru)) {
+ eb = list_entry(fs_info->lru.next, struct extent_buffer, lru);
+ if (eb->refs) {
+ /*
+ * Reset extent buffer refs to 1, so the
+ * free_extent_buffer_nocache() can free it for sure.
+ */
+ eb->refs = 1;
+ fprintf(stderr,
+ "extent buffer leak: start %llu len %u\n",
+ (unsigned long long)eb->start, eb->len);
+ free_extent_buffer_nocache(eb);
+ } else {
+ free_extent_buffer_final(eb);
+ }
+ }
+
+ free_extent_cache_tree(&fs_info->extent_cache);
+ fs_info->cache_size = 0;
+}
+
void extent_io_tree_init(struct extent_io_tree *tree)
{
cache_tree_init(&tree->state);
cache_tree_init(&tree->cache);
INIT_LIST_HEAD(&tree->lru);
- tree->cache_size = 0;
- tree->max_cache_size = (u64)total_memory() / 4;
}
static struct extent_state *alloc_extent_state(void)
@@ -73,7 +105,6 @@ static void free_extent_state_func(struct cache_extent *cache)
btrfs_free_extent_state(es);
}
-static void free_extent_buffer_final(struct extent_buffer *eb);
void extent_io_tree_cleanup(struct extent_io_tree *tree)
{
struct extent_buffer *eb;
@@ -644,11 +675,9 @@ static void free_extent_buffer_final(struct extent_buffer *eb)
BUG_ON(eb->refs);
list_del_init(&eb->lru);
if (!(eb->flags & EXTENT_BUFFER_DUMMY)) {
- struct extent_io_tree *tree = &eb->fs_info->extent_cache;
-
- remove_cache_extent(&tree->cache, &eb->cache_node);
- BUG_ON(tree->cache_size < eb->len);
- tree->cache_size -= eb->len;
+ remove_cache_extent(&eb->fs_info->extent_cache, &eb->cache_node);
+ BUG_ON(eb->fs_info->cache_size < eb->len);
+ eb->fs_info->cache_size -= eb->len;
}
free(eb);
}
@@ -685,15 +714,14 @@ void free_extent_buffer_nocache(struct extent_buffer *eb)
struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info,
u64 bytenr, u32 blocksize)
{
- struct extent_io_tree *tree = &fs_info->extent_cache;
struct extent_buffer *eb = NULL;
struct cache_extent *cache;
- cache = lookup_cache_extent(&tree->cache, bytenr, blocksize);
+ cache = lookup_cache_extent(&fs_info->extent_cache, bytenr, blocksize);
if (cache && cache->start == bytenr &&
cache->size == blocksize) {
eb = container_of(cache, struct extent_buffer, cache_node);
- list_move_tail(&eb->lru, &tree->lru);
+ list_move_tail(&eb->lru, &fs_info->lru);
eb->refs++;
}
return eb;
@@ -702,27 +730,26 @@ struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info,
struct extent_buffer *find_first_extent_buffer(struct btrfs_fs_info *fs_info,
u64 start)
{
- struct extent_io_tree *tree = &fs_info->extent_cache;
struct extent_buffer *eb = NULL;
struct cache_extent *cache;
- cache = search_cache_extent(&tree->cache, start);
+ cache = search_cache_extent(&fs_info->extent_cache, start);
if (cache) {
eb = container_of(cache, struct extent_buffer, cache_node);
- list_move_tail(&eb->lru, &tree->lru);
+ list_move_tail(&eb->lru, &fs_info->lru);
eb->refs++;
}
return eb;
}
-static void trim_extent_buffer_cache(struct extent_io_tree *tree)
+static void trim_extent_buffer_cache(struct btrfs_fs_info *fs_info)
{
struct extent_buffer *eb, *tmp;
- list_for_each_entry_safe(eb, tmp, &tree->lru, lru) {
+ list_for_each_entry_safe(eb, tmp, &fs_info->lru, lru) {
if (eb->refs == 0)
free_extent_buffer_final(eb);
- if (tree->cache_size <= ((tree->max_cache_size * 9) / 10))
+ if (fs_info->cache_size <= ((fs_info->max_cache_size * 9) / 10))
break;
}
}
@@ -731,14 +758,13 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
u64 bytenr, u32 blocksize)
{
struct extent_buffer *eb;
- struct extent_io_tree *tree = &fs_info->extent_cache;
struct cache_extent *cache;
- cache = lookup_cache_extent(&tree->cache, bytenr, blocksize);
+ cache = lookup_cache_extent(&fs_info->extent_cache, bytenr, blocksize);
if (cache && cache->start == bytenr &&
cache->size == blocksize) {
eb = container_of(cache, struct extent_buffer, cache_node);
- list_move_tail(&eb->lru, &tree->lru);
+ list_move_tail(&eb->lru, &fs_info->lru);
eb->refs++;
} else {
int ret;
@@ -751,15 +777,15 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
eb = __alloc_extent_buffer(fs_info, bytenr, blocksize);
if (!eb)
return NULL;
- ret = insert_cache_extent(&tree->cache, &eb->cache_node);
+ ret = insert_cache_extent(&fs_info->extent_cache, &eb->cache_node);
if (ret) {
free(eb);
return NULL;
}
- list_add_tail(&eb->lru, &tree->lru);
- tree->cache_size += blocksize;
- if (tree->cache_size >= tree->max_cache_size)
- trim_extent_buffer_cache(tree);
+ list_add_tail(&eb->lru, &fs_info->lru);
+ fs_info->cache_size += blocksize;
+ if (fs_info->cache_size >= fs_info->max_cache_size)
+ trim_extent_buffer_cache(fs_info);
}
return eb;
}
@@ -165,5 +165,7 @@ void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start,
unsigned long pos, unsigned long len);
void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start,
unsigned long pos, unsigned long len);
+void extent_buffer_init_cache(struct btrfs_fs_info *fs_info);
+void extent_buffer_free_cache(struct btrfs_fs_info *fs_info);
#endif
We have some extra features in the btrfs-progs copy of the extent_io_tree that don't exist in the kernel. In order to make syncing easier simply move this functionality into btrfs_fs_info, that way we can sync in the new extent_io_tree code and not have to worry about breaking anything. Signed-off-by: Josef Bacik <josef@toxicpanda.com> --- kernel-shared/ctree.h | 6 +++- kernel-shared/disk-io.c | 4 +-- kernel-shared/extent_io.c | 76 ++++++++++++++++++++++++++------------- kernel-shared/extent_io.h | 2 ++ 4 files changed, 60 insertions(+), 28 deletions(-)