/* * Utility function to look for merge candidates inside a given range. * Any extents with matching state are merged together into a single * extent in the tree. Extents with EXTENT_IO in their state field are * not merged */ static int merge_state(struct extent_io_tree *tree, struct extent_state *state) { struct extent_state *other; struct cache_extent *other_node; if (state->state & EXTENT_IOBITS) return 0; other_node = prev_cache_extent(&state->cache_node); if (other_node) { other = container_of(other_node, struct extent_state, cache_node); if (other->end == state->start - 1 && other->state == state->state) { state->start = other->start; update_extent_state(state); remove_cache_extent(&tree->state, &other->cache_node); btrfs_free_extent_state(other); } } other_node = next_cache_extent(&state->cache_node); if (other_node) { other = container_of(other_node, struct extent_state, cache_node); if (other->start == state->end + 1 && other->state == state->state) { other->start = state->start; update_extent_state(other); remove_cache_extent(&tree->state, &state->cache_node); btrfs_free_extent_state(state); } } return 0; }
void extent_io_tree_cleanup(struct extent_io_tree *tree) { struct extent_state *es; struct extent_buffer *eb; struct cache_extent *cache; while(!list_empty(&tree->lru)) { eb = list_entry(tree->lru.next, struct extent_buffer, lru); if (eb->refs != 1) { fprintf(stderr, "extent buffer leak: " "start %llu len %u\n", (unsigned long long)eb->start, eb->len); eb->refs = 1; } free_extent_buffer(eb); } while (1) { cache = find_first_cache_extent(&tree->state, 0); if (!cache) break; es = container_of(cache, struct extent_state, cache_node); remove_cache_extent(&tree->state, &es->cache_node); free_extent_state(es); } }
/* * clear some bits on a range in the tree. */ static int clear_state_bit(struct extent_io_tree *tree, struct extent_state *state, int bits) { int ret = state->state & bits; state->state &= ~bits; if (state->state == 0) { remove_cache_extent(&tree->state, &state->cache_node); btrfs_free_extent_state(state); } else { merge_state(tree, state); } return ret; }
static int free_fs_roots(struct btrfs_fs_info *fs_info) { struct cache_extent *cache; struct btrfs_root *root; while (1) { cache = find_first_cache_extent(&fs_info->fs_root_cache, 0); if (!cache) break; root = container_of(cache, struct btrfs_root, cache); remove_cache_extent(&fs_info->fs_root_cache, cache); btrfs_free_fs_root(fs_info, root); } return 0; }