diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-08-10 14:42:37 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-08-10 14:42:37 -0400 |
commit | f2183bde1a918d338337955c8e8ba29bd8f5e7b1 (patch) | |
tree | e27baea3779112618d2158902270c460444feeff | |
parent | e9d0b13b5bbb58c9b840e407a8d181442f799966 (diff) |
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: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/ctree.c | 22 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 2 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 2 | ||||
-rw-r--r-- | fs/btrfs/tree-defrag.c | 3 |
4 files changed, 18 insertions, 11 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index ee1ae00d2827..7cf43da5e78e 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -175,6 +175,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, int end_slot; int i; int err = 0; + int parent_level; if (trans->transaction != root->fs_info->running_transaction) { printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid, @@ -188,6 +189,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, } parent_node = btrfs_buffer_node(parent); parent_nritems = btrfs_header_nritems(&parent_node->header); + parent_level = btrfs_header_level(&parent_node->header); start_slot = 0; end_slot = parent_nritems; @@ -215,13 +217,16 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, cur_bh = btrfs_find_tree_block(root, blocknr); if (!cur_bh || !buffer_uptodate(cur_bh) || - buffer_locked(cur_bh)) { + buffer_locked(cur_bh) || !buffer_defrag(cur_bh)) { if (cache_only) { brelse(cur_bh); continue; } - brelse(cur_bh); - cur_bh = read_tree_block(root, blocknr); + if (!cur_bh || !buffer_uptodate(cur_bh) || + buffer_locked(cur_bh)) { + brelse(cur_bh); + cur_bh = read_tree_block(root, blocknr); + } } if (search_start == 0) search_start = last_block & ~((u64)65535); @@ -232,6 +237,9 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, if (err) break; search_start = bh_blocknr(tmp_bh); + *last_ret = search_start; + if (parent_level == 1) + clear_buffer_defrag(tmp_bh); brelse(tmp_bh); } return err; @@ -811,16 +819,10 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, clear_radix_bit(&found, blocknr); if (nread > 32) continue; - if (direction > 0 && cluster_start <= blocknr && - cluster_start + 8 > blocknr) { - cluster_start = blocknr; + if (close_blocks(cluster_start, blocknr)) { readahead_tree_block(root, blocknr); nread++; - } else if (direction < 0 && cluster_start >= blocknr && - blocknr + 8 > cluster_start) { cluster_start = blocknr; - readahead_tree_block(root, blocknr); - nread++; } } } diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 9e2c261b41ae..81fd18cbd824 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h @@ -25,8 +25,10 @@ enum btrfs_bh_state_bits { BH_Checked = BH_PrivateStart, + BH_Defrag, }; BUFFER_FNS(Checked, checked); +BUFFER_FNS(Defrag, defrag); static inline struct btrfs_node *btrfs_buffer_node(struct buffer_head *bh) { diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 3418bb62b996..b3641234473f 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1015,6 +1015,7 @@ check_failed: ins->objectid = search_start; ins->offset = 0; start_found = 0; + path->reada = 1; ret = btrfs_search_slot(trans, root, ins, path, 0, 0); if (ret < 0) @@ -1264,6 +1265,7 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, WARN_ON(buffer_dirty(buf)); set_buffer_uptodate(buf); set_buffer_checked(buf); + set_buffer_defrag(buf); set_radix_bit(&trans->transaction->dirty_pages, buf->b_page->index); return buf; } diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c index a09064a9a41c..35fd20d24645 100644 --- a/fs/btrfs/tree-defrag.c +++ b/fs/btrfs/tree-defrag.c @@ -86,7 +86,7 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans, if (cache_only) { next = btrfs_find_tree_block(root, blocknr); if (!next || !buffer_uptodate(next) || - buffer_locked(next)) { + buffer_locked(next) || !buffer_defrag(next)) { brelse(next); path->slots[*level]++; continue; @@ -142,6 +142,7 @@ static int defrag_walk_up(struct btrfs_trans_handle *trans, root->defrag_level = i; return 0; } else { + clear_buffer_defrag(path->nodes[*level]); btrfs_block_release(root, path->nodes[*level]); path->nodes[*level] = NULL; *level = i + 1; |