Commit f2183bde authored by Chris Mason's avatar Chris Mason Committed by David Woodhouse

Btrfs: Add BH_Defrag to mark buffers that are in need of defragging

This allows the tree walking code to defrag only the newly allocated
buffers, it seems to be a good balance between perfect defragging and the
performance hit of repeatedly reallocating blocks.
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent e9d0b13b
...@@ -175,6 +175,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, ...@@ -175,6 +175,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
int end_slot; int end_slot;
int i; int i;
int err = 0; int err = 0;
int parent_level;
if (trans->transaction != root->fs_info->running_transaction) { if (trans->transaction != root->fs_info->running_transaction) {
printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid, printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid,
...@@ -188,6 +189,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, ...@@ -188,6 +189,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
} }
parent_node = btrfs_buffer_node(parent); parent_node = btrfs_buffer_node(parent);
parent_nritems = btrfs_header_nritems(&parent_node->header); parent_nritems = btrfs_header_nritems(&parent_node->header);
parent_level = btrfs_header_level(&parent_node->header);
start_slot = 0; start_slot = 0;
end_slot = parent_nritems; end_slot = parent_nritems;
...@@ -215,13 +217,16 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, ...@@ -215,13 +217,16 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
cur_bh = btrfs_find_tree_block(root, blocknr); cur_bh = btrfs_find_tree_block(root, blocknr);
if (!cur_bh || !buffer_uptodate(cur_bh) || if (!cur_bh || !buffer_uptodate(cur_bh) ||
buffer_locked(cur_bh)) { buffer_locked(cur_bh) || !buffer_defrag(cur_bh)) {
if (cache_only) { if (cache_only) {
brelse(cur_bh); brelse(cur_bh);
continue; continue;
} }
brelse(cur_bh); if (!cur_bh || !buffer_uptodate(cur_bh) ||
cur_bh = read_tree_block(root, blocknr); buffer_locked(cur_bh)) {
brelse(cur_bh);
cur_bh = read_tree_block(root, blocknr);
}
} }
if (search_start == 0) if (search_start == 0)
search_start = last_block & ~((u64)65535); search_start = last_block & ~((u64)65535);
...@@ -232,6 +237,9 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, ...@@ -232,6 +237,9 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
if (err) if (err)
break; break;
search_start = bh_blocknr(tmp_bh); search_start = bh_blocknr(tmp_bh);
*last_ret = search_start;
if (parent_level == 1)
clear_buffer_defrag(tmp_bh);
brelse(tmp_bh); brelse(tmp_bh);
} }
return err; return err;
...@@ -811,16 +819,10 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, ...@@ -811,16 +819,10 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
clear_radix_bit(&found, blocknr); clear_radix_bit(&found, blocknr);
if (nread > 32) if (nread > 32)
continue; continue;
if (direction > 0 && cluster_start <= blocknr && if (close_blocks(cluster_start, blocknr)) {
cluster_start + 8 > blocknr) {
cluster_start = blocknr;
readahead_tree_block(root, blocknr); readahead_tree_block(root, blocknr);
nread++; nread++;
} else if (direction < 0 && cluster_start >= blocknr &&
blocknr + 8 > cluster_start) {
cluster_start = blocknr; cluster_start = blocknr;
readahead_tree_block(root, blocknr);
nread++;
} }
} }
} }
......
...@@ -25,8 +25,10 @@ ...@@ -25,8 +25,10 @@
enum btrfs_bh_state_bits { enum btrfs_bh_state_bits {
BH_Checked = BH_PrivateStart, BH_Checked = BH_PrivateStart,
BH_Defrag,
}; };
BUFFER_FNS(Checked, checked); BUFFER_FNS(Checked, checked);
BUFFER_FNS(Defrag, defrag);
static inline struct btrfs_node *btrfs_buffer_node(struct buffer_head *bh) static inline struct btrfs_node *btrfs_buffer_node(struct buffer_head *bh)
{ {
......
...@@ -1015,6 +1015,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1015,6 +1015,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
ins->objectid = search_start; ins->objectid = search_start;
ins->offset = 0; ins->offset = 0;
start_found = 0; start_found = 0;
path->reada = 1;
ret = btrfs_search_slot(trans, root, ins, path, 0, 0); ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
if (ret < 0) if (ret < 0)
...@@ -1264,6 +1265,7 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, ...@@ -1264,6 +1265,7 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
WARN_ON(buffer_dirty(buf)); WARN_ON(buffer_dirty(buf));
set_buffer_uptodate(buf); set_buffer_uptodate(buf);
set_buffer_checked(buf); set_buffer_checked(buf);
set_buffer_defrag(buf);
set_radix_bit(&trans->transaction->dirty_pages, buf->b_page->index); set_radix_bit(&trans->transaction->dirty_pages, buf->b_page->index);
return buf; return buf;
} }
......
...@@ -86,7 +86,7 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans, ...@@ -86,7 +86,7 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans,
if (cache_only) { if (cache_only) {
next = btrfs_find_tree_block(root, blocknr); next = btrfs_find_tree_block(root, blocknr);
if (!next || !buffer_uptodate(next) || if (!next || !buffer_uptodate(next) ||
buffer_locked(next)) { buffer_locked(next) || !buffer_defrag(next)) {
brelse(next); brelse(next);
path->slots[*level]++; path->slots[*level]++;
continue; continue;
...@@ -142,6 +142,7 @@ static int defrag_walk_up(struct btrfs_trans_handle *trans, ...@@ -142,6 +142,7 @@ static int defrag_walk_up(struct btrfs_trans_handle *trans,
root->defrag_level = i; root->defrag_level = i;
return 0; return 0;
} else { } else {
clear_buffer_defrag(path->nodes[*level]);
btrfs_block_release(root, path->nodes[*level]); btrfs_block_release(root, path->nodes[*level]);
path->nodes[*level] = NULL; path->nodes[*level] = NULL;
*level = i + 1; *level = i + 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment