aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-08-27 16:49:44 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-08-27 16:49:44 -0400
commit2cc58cf24f69be8632a3b29d653c318bf3bd8c84 (patch)
treeca7eeec52113f8b4c1e45743da72e1b227aa4e34 /fs
parent320206112895c72f98e57570ae194689dcd7fe56 (diff)
Btrfs: Do more extensive readahead during tree searches
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.c62
-rw-r--r--fs/btrfs/extent-tree.c4
-rw-r--r--fs/btrfs/inode.c2
3 files changed, 52 insertions, 16 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 51eea5ccb645..c0782a5b04c5 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -43,8 +43,10 @@ struct btrfs_path *btrfs_alloc_path(void)
43{ 43{
44 struct btrfs_path *path; 44 struct btrfs_path *path;
45 path = kmem_cache_alloc(btrfs_path_cachep, GFP_NOFS); 45 path = kmem_cache_alloc(btrfs_path_cachep, GFP_NOFS);
46 if (path) 46 if (path) {
47 btrfs_init_path(path); 47 btrfs_init_path(path);
48 path->reada = 1;
49 }
48 return path; 50 return path;
49} 51}
50 52
@@ -159,6 +161,34 @@ static int close_blocks(u64 blocknr, u64 other)
159 return 0; 161 return 0;
160} 162}
161 163
164static int should_defrag_leaf(struct buffer_head *bh)
165{
166 struct btrfs_leaf *leaf = btrfs_buffer_leaf(bh);
167 struct btrfs_disk_key *key;
168 u32 nritems;
169
170 if (buffer_defrag(bh))
171 return 1;
172
173 nritems = btrfs_header_nritems(&leaf->header);
174 if (nritems == 0)
175 return 0;
176
177 key = &leaf->items[0].key;
178 if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY)
179 return 1;
180
181 key = &leaf->items[nritems-1].key;
182 if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY)
183 return 1;
184 if (nritems > 4) {
185 key = &leaf->items[nritems/2].key;
186 if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY)
187 return 1;
188 }
189 return 0;
190}
191
162int btrfs_realloc_node(struct btrfs_trans_handle *trans, 192int btrfs_realloc_node(struct btrfs_trans_handle *trans,
163 struct btrfs_root *root, struct buffer_head *parent, 193 struct btrfs_root *root, struct buffer_head *parent,
164 int cache_only, u64 *last_ret) 194 int cache_only, u64 *last_ret)
@@ -217,7 +247,9 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
217 247
218 cur_bh = btrfs_find_tree_block(root, blocknr); 248 cur_bh = btrfs_find_tree_block(root, blocknr);
219 if (!cur_bh || !buffer_uptodate(cur_bh) || 249 if (!cur_bh || !buffer_uptodate(cur_bh) ||
220 buffer_locked(cur_bh) || !buffer_defrag(cur_bh)) { 250 buffer_locked(cur_bh) ||
251 (parent_level != 1 && !buffer_defrag(cur_bh)) ||
252 (parent_level == 1 && !should_defrag_leaf(cur_bh))) {
221 if (cache_only) { 253 if (cache_only) {
222 brelse(cur_bh); 254 brelse(cur_bh);
223 continue; 255 continue;
@@ -297,6 +329,7 @@ static int check_node(struct btrfs_root *root, struct btrfs_path *path,
297 parent = btrfs_buffer_node(path->nodes[level + 1]); 329 parent = btrfs_buffer_node(path->nodes[level + 1]);
298 330
299 slot = path->slots[level]; 331 slot = path->slots[level];
332 BUG_ON(!buffer_uptodate(path->nodes[level]));
300 BUG_ON(nritems == 0); 333 BUG_ON(nritems == 0);
301 if (parent) { 334 if (parent) {
302 struct btrfs_disk_key *parent_key; 335 struct btrfs_disk_key *parent_key;
@@ -511,9 +544,6 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
511 err_on_enospc = 1; 544 err_on_enospc = 1;
512 545
513 left_buf = read_node_slot(root, parent_buf, pslot - 1); 546 left_buf = read_node_slot(root, parent_buf, pslot - 1);
514 right_buf = read_node_slot(root, parent_buf, pslot + 1);
515
516 /* first, try to make some room in the middle buffer */
517 if (left_buf) { 547 if (left_buf) {
518 wret = btrfs_cow_block(trans, root, left_buf, 548 wret = btrfs_cow_block(trans, root, left_buf,
519 parent_buf, pslot - 1, &left_buf); 549 parent_buf, pslot - 1, &left_buf);
@@ -521,6 +551,19 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
521 ret = wret; 551 ret = wret;
522 goto enospc; 552 goto enospc;
523 } 553 }
554 }
555 right_buf = read_node_slot(root, parent_buf, pslot + 1);
556 if (right_buf) {
557 wret = btrfs_cow_block(trans, root, right_buf,
558 parent_buf, pslot + 1, &right_buf);
559 if (wret) {
560 ret = wret;
561 goto enospc;
562 }
563 }
564
565 /* first, try to make some room in the middle buffer */
566 if (left_buf) {
524 left = btrfs_buffer_node(left_buf); 567 left = btrfs_buffer_node(left_buf);
525 orig_slot += btrfs_header_nritems(&left->header); 568 orig_slot += btrfs_header_nritems(&left->header);
526 wret = push_node_left(trans, root, left_buf, mid_buf); 569 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
534 * then try to empty the right most buffer into the middle 577 * then try to empty the right most buffer into the middle
535 */ 578 */
536 if (right_buf) { 579 if (right_buf) {
537 wret = btrfs_cow_block(trans, root, right_buf,
538 parent_buf, pslot + 1, &right_buf);
539 if (wret) {
540 ret = wret;
541 goto enospc;
542 }
543
544 right = btrfs_buffer_node(right_buf); 580 right = btrfs_buffer_node(right_buf);
545 wret = push_node_left(trans, root, mid_buf, right_buf); 581 wret = push_node_left(trans, root, mid_buf, right_buf);
546 if (wret < 0 && wret != -ENOSPC) 582 if (wret < 0 && wret != -ENOSPC)
@@ -817,7 +853,7 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
817 for (i = 0; i < ret; i++) { 853 for (i = 0; i < ret; i++) {
818 blocknr = gang[i]; 854 blocknr = gang[i];
819 clear_radix_bit(&found, blocknr); 855 clear_radix_bit(&found, blocknr);
820 if (nread > 32) 856 if (path->reada == 1 && nread > 16)
821 continue; 857 continue;
822 if (close_blocks(cluster_start, blocknr)) { 858 if (close_blocks(cluster_start, blocknr)) {
823 readahead_tree_block(root, blocknr); 859 readahead_tree_block(root, blocknr);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index b3641234473f..4049aadbeda9 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -52,7 +52,7 @@ static int cache_block_group(struct btrfs_root *root,
52 path = btrfs_alloc_path(); 52 path = btrfs_alloc_path();
53 if (!path) 53 if (!path)
54 return -ENOMEM; 54 return -ENOMEM;
55 path->reada = 1; 55 path->reada = 2;
56 key.objectid = block_group->key.objectid; 56 key.objectid = block_group->key.objectid;
57 key.flags = 0; 57 key.flags = 0;
58 key.offset = 0; 58 key.offset = 0;
@@ -1015,7 +1015,7 @@ check_failed:
1015 ins->objectid = search_start; 1015 ins->objectid = search_start;
1016 ins->offset = 0; 1016 ins->offset = 0;
1017 start_found = 0; 1017 start_found = 0;
1018 path->reada = 1; 1018 path->reada = 2;
1019 1019
1020 ret = btrfs_search_slot(trans, root, ins, path, 0, 0); 1020 ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
1021 if (ret < 0) 1021 if (ret < 0)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 398484179d82..7e4cf62ada5a 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -827,7 +827,7 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
827 btrfs_set_key_type(&key, key_type); 827 btrfs_set_key_type(&key, key_type);
828 key.offset = filp->f_pos; 828 key.offset = filp->f_pos;
829 path = btrfs_alloc_path(); 829 path = btrfs_alloc_path();
830 path->reada = 1; 830 path->reada = 2;
831 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 831 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
832 if (ret < 0) 832 if (ret < 0)
833 goto err; 833 goto err;