X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=extent-cache.c;h=38bed8b5db70d8550f19d5b6dafca8b2f8ad457c;hb=1d5058058a811a03a1985d18ff3071ce95b99c08;hp=a09fe8709f317aec9101463ed9f6dd561dc3f9b4;hpb=d35300269709a0588b3252373c70eb94df7520fe;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/extent-cache.c b/extent-cache.c index a09fe87..38bed8b 100644 --- a/extent-cache.c +++ b/extent-cache.c @@ -19,17 +19,14 @@ #include #include "kerncompat.h" #include "extent-cache.h" +#include "rbtree-utils.h" struct cache_extent_search_range { + u64 objectid; u64 start; u64 size; }; -void cache_tree_init(struct cache_tree *tree) -{ - tree->root = RB_ROOT; -} - static int cache_tree_comp_range(struct rb_node *node, void *data) { struct cache_extent *entry; @@ -58,26 +55,62 @@ static int cache_tree_comp_nodes(struct rb_node *node1, struct rb_node *node2) return cache_tree_comp_range(node1, (void *)&range); } -struct cache_extent *alloc_cache_extent(u64 start, u64 size) +static int cache_tree_comp_range2(struct rb_node *node, void *data) +{ + struct cache_extent *entry; + struct cache_extent_search_range *range; + + range = (struct cache_extent_search_range *)data; + entry = rb_entry(node, struct cache_extent, rb_node); + + if (entry->objectid < range->objectid) + return 1; + else if (entry->objectid > range->objectid) + return -1; + else if (entry->start + entry->size <= range->start) + return 1; + else if (range->start + range->size <= entry->start) + return -1; + else + return 0; +} + +static int cache_tree_comp_nodes2(struct rb_node *node1, struct rb_node *node2) +{ + struct cache_extent *entry; + struct cache_extent_search_range range; + + entry = rb_entry(node2, struct cache_extent, rb_node); + range.objectid = entry->objectid; + range.start = entry->start; + range.size = entry->size; + + return cache_tree_comp_range2(node1, (void *)&range); +} + +void cache_tree_init(struct cache_tree *tree) +{ + tree->root = RB_ROOT; +} + +static struct cache_extent * +alloc_cache_extent(u64 objectid, u64 start, u64 size) { struct cache_extent *pe = malloc(sizeof(*pe)); if (!pe) return pe; + pe->objectid = objectid; pe->start = start; pe->size = size; return pe; } -int insert_cache_extent(struct cache_tree *tree, struct cache_extent *pe) -{ - return rb_insert(&tree->root, &pe->rb_node, cache_tree_comp_nodes); -} - -int add_cache_extent(struct cache_tree *tree, u64 start, u64 size) +static int __add_cache_extent(struct cache_tree *tree, + u64 objectid, u64 start, u64 size) { - struct cache_extent *pe = alloc_cache_extent(start, size); + struct cache_extent *pe = alloc_cache_extent(objectid, start, size); int ret; if (!pe) { @@ -92,8 +125,29 @@ int add_cache_extent(struct cache_tree *tree, u64 start, u64 size) return ret; } -struct cache_extent *find_cache_extent(struct cache_tree *tree, - u64 start, u64 size) +int add_cache_extent(struct cache_tree *tree, u64 start, u64 size) +{ + return __add_cache_extent(tree, 0, start, size); +} + +int add_cache_extent2(struct cache_tree *tree, + u64 objectid, u64 start, u64 size) +{ + return __add_cache_extent(tree, objectid, start, size); +} + +int insert_cache_extent(struct cache_tree *tree, struct cache_extent *pe) +{ + return rb_insert(&tree->root, &pe->rb_node, cache_tree_comp_nodes); +} + +int insert_cache_extent2(struct cache_tree *tree, struct cache_extent *pe) +{ + return rb_insert(&tree->root, &pe->rb_node, cache_tree_comp_nodes2); +} + +struct cache_extent *lookup_cache_extent(struct cache_tree *tree, + u64 start, u64 size) { struct rb_node *node; struct cache_extent *entry; @@ -109,7 +163,25 @@ struct cache_extent *find_cache_extent(struct cache_tree *tree, return entry; } -struct cache_extent *find_first_cache_extent(struct cache_tree *tree, u64 start) +struct cache_extent *lookup_cache_extent2(struct cache_tree *tree, + u64 objectid, u64 start, u64 size) +{ + struct rb_node *node; + struct cache_extent *entry; + struct cache_extent_search_range range; + + range.objectid = objectid; + range.start = start; + range.size = size; + node = rb_search(&tree->root, &range, cache_tree_comp_range2, NULL); + if (!node) + return NULL; + + entry = rb_entry(node, struct cache_extent, rb_node); + return entry; +} + +struct cache_extent *search_cache_extent(struct cache_tree *tree, u64 start) { struct rb_node *next; struct rb_node *node; @@ -128,6 +200,27 @@ struct cache_extent *find_first_cache_extent(struct cache_tree *tree, u64 start) return entry; } +struct cache_extent *search_cache_extent2(struct cache_tree *tree, + u64 objectid, u64 start) +{ + struct rb_node *next; + struct rb_node *node; + struct cache_extent *entry; + struct cache_extent_search_range range; + + range.objectid = objectid; + range.start = start; + range.size = 1; + node = rb_search(&tree->root, &range, cache_tree_comp_range2, &next); + if (!node) + node = next; + if (!node) + return NULL; + + entry = rb_entry(node, struct cache_extent, rb_node); + return entry; +} + struct cache_extent *first_cache_extent(struct cache_tree *tree) { struct rb_node *node = rb_first(&tree->root); @@ -137,6 +230,15 @@ struct cache_extent *first_cache_extent(struct cache_tree *tree) return rb_entry(node, struct cache_extent, rb_node); } +struct cache_extent *last_cache_extent(struct cache_tree *tree) +{ + struct rb_node *node = rb_last(&tree->root); + + if (!node) + return NULL; + return rb_entry(node, struct cache_extent, rb_node); +} + struct cache_extent *prev_cache_extent(struct cache_extent *pe) { struct rb_node *node = rb_prev(&pe->rb_node); @@ -170,3 +272,70 @@ void cache_tree_free_extents(struct cache_tree *tree, free_func(ce); } } + +static void free_extent_cache(struct cache_extent *pe) +{ + free(pe); +} + +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; +}