Skip to content

Commit

Permalink
Btrfs: Improve space balancing code
Browse files Browse the repository at this point in the history
This patch improves the space balancing code to keep more sharing
of tree blocks. The only case that breaks sharing of tree blocks is
data extents get fragmented during balancing. The main changes in
this patch are:

Add a 'drop sub-tree' function. This solves the problem in old code
that BTRFS_HEADER_FLAG_WRITTEN check breaks sharing of tree block.

Remove relocation mapping tree. Relocation mappings are stored in
struct btrfs_ref_path and updated dynamically during walking up/down
the reference path. This reduces CPU usage and simplifies code.

This patch also fixes a bug. Root items for reloc trees should be
updated in btrfs_free_reloc_root.

Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
  • Loading branch information
Yan Zheng authored and Chris Mason committed Oct 29, 2008
1 parent c8b9781 commit f82d02d
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 199 deletions.
93 changes: 47 additions & 46 deletions fs/btrfs/ctree.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ int noinline __btrfs_cow_block(struct btrfs_trans_handle *trans,
/*
* There are only two places that can drop reference to
* tree blocks owned by living reloc trees, one is here,
* the other place is btrfs_merge_path. In both places,
* the other place is btrfs_drop_subtree. In both places,
* we check reference count while tree block is locked.
* Furthermore, if reference count is one, it won't get
* increased by someone else.
Expand All @@ -312,9 +312,6 @@ int noinline __btrfs_cow_block(struct btrfs_trans_handle *trans,
}

if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) {
ret = btrfs_add_reloc_mapping(root, buf->start,
buf->len, cow->start);
BUG_ON(ret);
ret = btrfs_reloc_tree_cache_ref(trans, root, cow, buf->start);
WARN_ON(ret);
}
Expand Down Expand Up @@ -1627,61 +1624,57 @@ int btrfs_merge_path(struct btrfs_trans_handle *trans,
btrfs_node_key_to_cpu(eb, &key, slot);
key_match = !memcmp(&key, &node_keys[level - 1], sizeof(key));

if (generation == trans->transid) {
eb = read_tree_block(root, bytenr, blocksize,
generation);
btrfs_tree_lock(eb);
}

/*
* if node keys match and node pointer hasn't been modified
* in the running transaction, we can merge the path. for
* reloc trees, the node pointer check is skipped, this is
* because the reloc trees are fully controlled by the space
* balance code, no one else can modify them.
* blocks owened by reloc trees, the node pointer check is
* skipped, this is because these blocks are fully controlled
* by the space balance code, no one else can modify them.
*/
if (!nodes[level - 1] || !key_match ||
(generation == trans->transid &&
root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID)) {
next_level:
if (level == 1 || level == lowest_level + 1)
btrfs_header_owner(eb) != BTRFS_TREE_RELOC_OBJECTID)) {
if (level == 1 || level == lowest_level + 1) {
if (generation == trans->transid) {
btrfs_tree_unlock(eb);
free_extent_buffer(eb);
}
break;
}

eb = read_tree_block(root, bytenr, blocksize,
generation);
btrfs_tree_lock(eb);
if (generation != trans->transid) {
eb = read_tree_block(root, bytenr, blocksize,
generation);
btrfs_tree_lock(eb);
}

ret = btrfs_cow_block(trans, root, eb, parent, slot,
&eb, 0);
BUG_ON(ret);

if (root->root_key.objectid ==
BTRFS_TREE_RELOC_OBJECTID) {
if (!nodes[level - 1]) {
nodes[level - 1] = eb->start;
memcpy(&node_keys[level - 1], &key,
sizeof(node_keys[0]));
} else {
WARN_ON(1);
}
}

btrfs_tree_unlock(parent);
free_extent_buffer(parent);
parent = eb;
continue;
}

if (generation == trans->transid) {
u32 refs;
BUG_ON(btrfs_header_owner(eb) !=
BTRFS_TREE_RELOC_OBJECTID);
/*
* lock the block to keep __btrfs_cow_block from
* changing the reference count.
*/
eb = read_tree_block(root, bytenr, blocksize,
generation);
btrfs_tree_lock(eb);

ret = btrfs_lookup_extent_ref(trans, root, bytenr,
blocksize, &refs);
BUG_ON(ret);
/*
* if replace block whose reference count is one,
* we have to "drop the subtree". so skip it for
* simplicity
*/
if (refs == 1) {
btrfs_tree_unlock(eb);
free_extent_buffer(eb);
goto next_level;
}
}

btrfs_set_node_blockptr(parent, slot, nodes[level - 1]);
btrfs_set_node_ptr_generation(parent, slot, trans->transid);
btrfs_mark_buffer_dirty(parent);
Expand All @@ -1693,16 +1686,24 @@ int btrfs_merge_path(struct btrfs_trans_handle *trans,
btrfs_header_generation(parent),
level - 1);
BUG_ON(ret);
ret = btrfs_free_extent(trans, root, bytenr,
blocksize, parent->start,
btrfs_header_owner(parent),
btrfs_header_generation(parent),
level - 1, 1);
BUG_ON(ret);

/*
* If the block was created in the running transaction,
* it's possible this is the last reference to it, so we
* should drop the subtree.
*/
if (generation == trans->transid) {
ret = btrfs_drop_subtree(trans, root, eb, parent);
BUG_ON(ret);
btrfs_tree_unlock(eb);
free_extent_buffer(eb);
} else {
ret = btrfs_free_extent(trans, root, bytenr,
blocksize, parent->start,
btrfs_header_owner(parent),
btrfs_header_generation(parent),
level - 1, 1);
BUG_ON(ret);
}
break;
}
Expand Down
13 changes: 6 additions & 7 deletions fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,6 @@ struct btrfs_fs_info {
int thread_pool_size;

/* tree relocation relocated fields */
struct extent_io_tree reloc_mapping_tree;
struct list_head dead_reloc_roots;
struct btrfs_leaf_ref_tree reloc_ref_tree;
struct btrfs_leaf_ref_tree shared_ref_tree;
Expand Down Expand Up @@ -1636,13 +1635,9 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 group_start);
int btrfs_relocate_block_group(struct btrfs_root *root, u64 group_start);
int btrfs_free_reloc_root(struct btrfs_root *root);
int btrfs_free_reloc_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_drop_dead_reloc_roots(struct btrfs_root *root);
int btrfs_add_reloc_mapping(struct btrfs_root *root, u64 orig_bytenr,
u64 num_bytes, u64 new_bytenr);
int btrfs_get_reloc_mapping(struct btrfs_root *root, u64 orig_bytenr,
u64 num_bytes, u64 *new_bytenr);
void btrfs_free_reloc_mappings(struct btrfs_root *root);
int btrfs_reloc_tree_cache_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf, u64 orig_start);
Expand Down Expand Up @@ -1726,6 +1721,10 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
*root);
int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *node,
struct extent_buffer *parent);
/* root-item.c */
int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_key *key);
Expand Down
2 changes: 0 additions & 2 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -1448,8 +1448,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
fs_info->btree_inode->i_mapping, GFP_NOFS);
fs_info->do_barriers = 1;

extent_io_tree_init(&fs_info->reloc_mapping_tree,
fs_info->btree_inode->i_mapping, GFP_NOFS);
INIT_LIST_HEAD(&fs_info->dead_reloc_roots);
btrfs_leaf_ref_tree_init(&fs_info->reloc_ref_tree);
btrfs_leaf_ref_tree_init(&fs_info->shared_ref_tree);
Expand Down
Loading

0 comments on commit f82d02d

Please sign in to comment.