summaryrefslogtreecommitdiff
path: root/extent-cache.c
diff options
context:
space:
mode:
authorQu Wenruo <quwenruo@cn.fujitsu.com>2015-12-01 15:11:22 +0800
committerDavid Sterba <dsterba@suse.com>2016-01-12 15:01:03 +0100
commitf735b37466c293aa6ecc4d145b6251c162c519f6 (patch)
treec7bb26a6db860a23ba7230d323a87ba59c827edd /extent-cache.c
parent466e066837898ec047165b8f1081c529092c6d0a (diff)
btrfs-progs: extent-tree: Add add_merge_cache_extent function
This add_merge_cache_extent() function will try to merge adjusted cache_extent. This is used for later btrfs-convert ext2 free space cache. Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'extent-cache.c')
-rw-r--r--extent-cache.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/extent-cache.c b/extent-cache.c
index d80aead6..38bed8b5 100644
--- a/extent-cache.c
+++ b/extent-cache.c
@@ -282,3 +282,60 @@ void free_extent_cache_tree(struct cache_tree *tree)
{
cache_tree_free_extents(tree, free_extent_cache);
}
+
+int add_merge_cache_extent(struct cache_tree *tree, u64 start, u64 size)
+{
+ struct cache_extent *cache;
+ struct cache_extent *next = NULL;
+ struct cache_extent *prev = NULL;
+ int next_merged = 0;
+ int prev_merged = 0;
+ int ret = 0;
+
+ if (cache_tree_empty(tree))
+ goto insert;
+
+ cache = search_cache_extent(tree, start);
+ if (!cache) {
+ /*
+ * Either the tree is completely empty, or the no range after
+ * start.
+ * Either way, the last cache_extent should be prev.
+ */
+ prev = last_cache_extent(tree);
+ } else if (start <= cache->start) {
+ next = cache;
+ prev = prev_cache_extent(cache);
+ } else {
+ prev = cache;
+ next = next_cache_extent(cache);
+ }
+
+ /*
+ * Ensure the range to be inserted won't cover with existings
+ * Or we will need extra loop to do merge
+ */
+ BUG_ON(next && start + size > next->start);
+ BUG_ON(prev && prev->start + prev->size > start);
+
+ if (next && start + size == next->start) {
+ next_merged = 1;
+ next->size = next->start + next->size - start;
+ next->start = start;
+ }
+ if (prev && prev->start + prev->size == start) {
+ prev_merged = 1;
+ if (next_merged) {
+ next->size = next->start + next->size - prev->start;
+ next->start = prev->start;
+ remove_cache_extent(tree, prev);
+ free(prev);
+ } else {
+ prev->size = start + size - prev->start;
+ }
+ }
+insert:
+ if (!prev_merged && !next_merged)
+ ret = add_cache_extent(tree, start, size);
+ return ret;
+}