Btrfs: Do more extensive readahead during tree searches
authorChris Mason <chris.mason@oracle.com>
Mon, 27 Aug 2007 20:49:44 +0000 (16:49 -0400)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Mon, 27 Aug 2007 20:49:44 +0000 (16:49 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.c
fs/btrfs/extent-tree.c
fs/btrfs/inode.c

index 51eea5ccb64572e74345b2bf162216ce79d07805..c0782a5b04c5384390151a8fed6c75983207d6cc 100644 (file)
@@ -43,8 +43,10 @@ struct btrfs_path *btrfs_alloc_path(void)
 {
        struct btrfs_path *path;
        path = kmem_cache_alloc(btrfs_path_cachep, GFP_NOFS);
-       if (path)
+       if (path) {
                btrfs_init_path(path);
+               path->reada = 1;
+       }
        return path;
 }
 
@@ -159,6 +161,34 @@ static int close_blocks(u64 blocknr, u64 other)
        return 0;
 }
 
+static int should_defrag_leaf(struct buffer_head *bh)
+{
+       struct btrfs_leaf *leaf = btrfs_buffer_leaf(bh);
+       struct btrfs_disk_key *key;
+       u32 nritems;
+
+       if (buffer_defrag(bh))
+               return 1;
+
+       nritems = btrfs_header_nritems(&leaf->header);
+       if (nritems == 0)
+               return 0;
+
+       key = &leaf->items[0].key;
+       if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY)
+               return 1;
+
+       key = &leaf->items[nritems-1].key;
+       if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY)
+               return 1;
+       if (nritems > 4) {
+               key = &leaf->items[nritems/2].key;
+               if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY)
+                       return 1;
+       }
+       return 0;
+}
+
 int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                       struct btrfs_root *root, struct buffer_head *parent,
                       int cache_only, u64 *last_ret)
@@ -217,7 +247,9 @@ 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_defrag(cur_bh)) {
+                   buffer_locked(cur_bh) ||
+                   (parent_level != 1 && !buffer_defrag(cur_bh)) ||
+                   (parent_level == 1 && !should_defrag_leaf(cur_bh))) {
                        if (cache_only) {
                                brelse(cur_bh);
                                continue;
@@ -297,6 +329,7 @@ static int check_node(struct btrfs_root *root, struct btrfs_path *path,
                parent = btrfs_buffer_node(path->nodes[level + 1]);
 
        slot = path->slots[level];
+       BUG_ON(!buffer_uptodate(path->nodes[level]));
        BUG_ON(nritems == 0);
        if (parent) {
                struct btrfs_disk_key *parent_key;
@@ -511,9 +544,6 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
                err_on_enospc = 1;
 
        left_buf = read_node_slot(root, parent_buf, pslot - 1);
-       right_buf = read_node_slot(root, parent_buf, pslot + 1);
-
-       /* first, try to make some room in the middle buffer */
        if (left_buf) {
                wret = btrfs_cow_block(trans, root, left_buf,
                                       parent_buf, pslot - 1, &left_buf);
@@ -521,6 +551,19 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
                        ret = wret;
                        goto enospc;
                }
+       }
+       right_buf = read_node_slot(root, parent_buf, pslot + 1);
+       if (right_buf) {
+               wret = btrfs_cow_block(trans, root, right_buf,
+                                      parent_buf, pslot + 1, &right_buf);
+               if (wret) {
+                       ret = wret;
+                       goto enospc;
+               }
+       }
+
+       /* first, try to make some room in the middle buffer */
+       if (left_buf) {
                left = btrfs_buffer_node(left_buf);
                orig_slot += btrfs_header_nritems(&left->header);
                wret = push_node_left(trans, root, left_buf, mid_buf);
@@ -534,13 +577,6 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
         * then try to empty the right most buffer into the middle
         */
        if (right_buf) {
-               wret = btrfs_cow_block(trans, root, right_buf,
-                                      parent_buf, pslot + 1, &right_buf);
-               if (wret) {
-                       ret = wret;
-                       goto enospc;
-               }
-
                right = btrfs_buffer_node(right_buf);
                wret = push_node_left(trans, root, mid_buf, right_buf);
                if (wret < 0 && wret != -ENOSPC)
@@ -817,7 +853,7 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
                for (i = 0; i < ret; i++) {
                        blocknr = gang[i];
                        clear_radix_bit(&found, blocknr);
-                       if (nread > 32)
+                       if (path->reada == 1 && nread > 16)
                                continue;
                        if (close_blocks(cluster_start, blocknr)) {
                                readahead_tree_block(root, blocknr);
index b3641234473f59598a22471b8e418438ba8e1947..4049aadbeda941fbdf9384a16165da02dd1e05dc 100644 (file)
@@ -52,7 +52,7 @@ static int cache_block_group(struct btrfs_root *root,
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
-       path->reada = 1;
+       path->reada = 2;
        key.objectid = block_group->key.objectid;
        key.flags = 0;
        key.offset = 0;
@@ -1015,7 +1015,7 @@ check_failed:
        ins->objectid = search_start;
        ins->offset = 0;
        start_found = 0;
-       path->reada = 1;
+       path->reada = 2;
 
        ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
        if (ret < 0)
index 398484179d82ea39e137baf20be1af3a9f06516f..7e4cf62ada5ad324105f240de94e99d41e3a9025 100644 (file)
@@ -827,7 +827,7 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        btrfs_set_key_type(&key, key_type);
        key.offset = filp->f_pos;
        path = btrfs_alloc_path();
-       path->reada = 1;
+       path->reada = 2;
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
        if (ret < 0)
                goto err;