diff options
-rw-r--r-- | extent_io.c | 73 | ||||
-rw-r--r-- | extent_io.h | 4 | ||||
-rw-r--r-- | utils.c | 13 | ||||
-rw-r--r-- | utils.h | 2 |
4 files changed, 79 insertions, 13 deletions
diff --git a/extent_io.c b/extent_io.c index 1c6c1425..eda1fb6f 100644 --- a/extent_io.c +++ b/extent_io.c @@ -22,11 +22,13 @@ #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> +#include <stdbool.h> #include "kerncompat.h" #include "extent_io.h" #include "list.h" #include "ctree.h" #include "volumes.h" +#include "utils.h" #include "internal.h" void extent_io_tree_init(struct extent_io_tree *tree) @@ -35,6 +37,14 @@ void extent_io_tree_init(struct extent_io_tree *tree) cache_tree_init(&tree->cache); INIT_LIST_HEAD(&tree->lru); tree->cache_size = 0; + tree->max_cache_size = (u64)total_memory() / 4; +} + +void extent_io_tree_init_cache_max(struct extent_io_tree *tree, + u64 max_cache_size) +{ + extent_io_tree_init(tree); + tree->max_cache_size = max_cache_size; } static struct extent_state *alloc_extent_state(void) @@ -67,16 +77,21 @@ 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; while(!list_empty(&tree->lru)) { eb = list_entry(tree->lru.next, struct extent_buffer, lru); - fprintf(stderr, "extent buffer leak: " - "start %llu len %u\n", - (unsigned long long)eb->start, eb->len); - free_extent_buffer(eb); + if (eb->refs) { + 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); + } } cache_tree_free_extents(&tree->state, free_extent_state_func); @@ -567,7 +582,21 @@ struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src) return new; } -void free_extent_buffer(struct extent_buffer *eb) +static void free_extent_buffer_final(struct extent_buffer *eb) +{ + struct extent_io_tree *tree = eb->tree; + + BUG_ON(eb->refs); + BUG_ON(tree->cache_size < eb->len); + list_del_init(&eb->lru); + if (!(eb->flags & EXTENT_BUFFER_DUMMY)) { + remove_cache_extent(&tree->cache, &eb->cache_node); + tree->cache_size -= eb->len; + } + free(eb); +} + +static void free_extent_buffer_internal(struct extent_buffer *eb, bool free_now) { if (!eb || IS_ERR(eb)) return; @@ -575,19 +604,23 @@ void free_extent_buffer(struct extent_buffer *eb) eb->refs--; BUG_ON(eb->refs < 0); if (eb->refs == 0) { - struct extent_io_tree *tree = eb->tree; BUG_ON(eb->flags & EXTENT_DIRTY); - list_del_init(&eb->lru); list_del_init(&eb->recow); - if (!(eb->flags & EXTENT_BUFFER_DUMMY)) { - BUG_ON(tree->cache_size < eb->len); - remove_cache_extent(&tree->cache, &eb->cache_node); - tree->cache_size -= eb->len; - } - free(eb); + if (eb->flags & EXTENT_BUFFER_DUMMY || free_now) + free_extent_buffer_final(eb); } } +void free_extent_buffer(struct extent_buffer *eb) +{ + free_extent_buffer_internal(eb, 0); +} + +void free_extent_buffer_nocache(struct extent_buffer *eb) +{ + free_extent_buffer_internal(eb, 1); +} + struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree, u64 bytenr, u32 blocksize) { @@ -619,6 +652,18 @@ struct extent_buffer *find_first_extent_buffer(struct extent_io_tree *tree, return eb; } +static void trim_extent_buffer_cache(struct extent_io_tree *tree) +{ + struct extent_buffer *eb, *tmp; + + list_for_each_entry_safe(eb, tmp, &tree->lru, lru) { + if (eb->refs == 0) + free_extent_buffer_final(eb); + if (tree->cache_size <= ((tree->max_cache_size * 9) / 10)) + break; + } +} + struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, u64 bytenr, u32 blocksize) { @@ -649,6 +694,8 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, } list_add_tail(&eb->lru, &tree->lru); tree->cache_size += blocksize; + if (tree->cache_size >= tree->max_cache_size) + trim_extent_buffer_cache(tree); } return eb; } diff --git a/extent_io.h b/extent_io.h index e6174894..17a4a829 100644 --- a/extent_io.h +++ b/extent_io.h @@ -75,6 +75,7 @@ struct extent_io_tree { struct cache_tree cache; struct list_head lru; u64 cache_size; + u64 max_cache_size; }; struct extent_state { @@ -106,6 +107,8 @@ static inline void extent_buffer_get(struct extent_buffer *eb) } void extent_io_tree_init(struct extent_io_tree *tree); +void extent_io_tree_init_cache_max(struct extent_io_tree *tree, + u64 max_cache_size); void extent_io_tree_cleanup(struct extent_io_tree *tree); int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits); int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits); @@ -146,6 +149,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, u64 bytenr, u32 blocksize); struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src); void free_extent_buffer(struct extent_buffer *eb); +void free_extent_buffer_nocache(struct extent_buffer *eb); int read_extent_from_disk(struct extent_buffer *eb, unsigned long offset, unsigned long len); int write_extent_to_disk(struct extent_buffer *eb); @@ -24,6 +24,7 @@ #include <sys/mount.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/sysinfo.h> #include <uuid/uuid.h> #include <fcntl.h> #include <unistd.h> @@ -2688,3 +2689,15 @@ u8 rand_u8(void) void btrfs_config_init(void) { } + +/* Returns total size of main memory in bytes, -1UL if error. */ +unsigned long total_memory(void) +{ + struct sysinfo si; + + if (sysinfo(&si) < 0) { + error("can't determine memory size"); + return -1UL; + } + return si.totalram * si.mem_unit; /* bytes */ +} @@ -169,6 +169,8 @@ unsigned int get_unit_mode_from_arg(int *argc, char *argv[], int df_mode); int string_is_numerical(const char *str); int prefixcmp(const char *str, const char *prefix); +unsigned long total_memory(void); + /* * Global program state, configurable by command line and available to * functions without extra context passing. |