Btrfs: Add BH_Defrag to mark buffers that are in need of defragging
authorChris Mason <chris.mason@oracle.com>
Fri, 10 Aug 2007 18:42:37 +0000 (14:42 -0400)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Fri, 10 Aug 2007 18:42:37 +0000 (14:42 -0400)
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>
fs/btrfs/ctree.c
fs/btrfs/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/tree-defrag.c

index ee1ae00d2827a34dff02d93f557b3ba5df861c52..7cf43da5e78e20f62840ec07276307fdccc14829 100644 (file)
@@ -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++;
                        }
                }
        }
index 9e2c261b41aead53c986533e29e69d3dd1e646ab..81fd18cbd82497fd8043858e6778018ad2e6039b 100644 (file)
 
 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)
 {
index 3418bb62b99676a0abe536a507ff586b31b871c8..b3641234473f59598a22471b8e418438ba8e1947 100644 (file)
@@ -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;
 }
index a09064a9a41cc9f549e4f9bfea352a1bde5941a8..35fd20d2464557f11ad2e73c8e5c17d4b8f0a171 100644 (file)
@@ -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;