diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-08-27 16:49:44 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-08-27 16:49:44 -0400 |
commit | 2cc58cf24f69be8632a3b29d653c318bf3bd8c84 (patch) | |
tree | ca7eeec52113f8b4c1e45743da72e1b227aa4e34 /fs | |
parent | 320206112895c72f98e57570ae194689dcd7fe56 (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.c | 62 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 4 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 2 |
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 | ||
164 | static 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 | |||
162 | int btrfs_realloc_node(struct btrfs_trans_handle *trans, | 192 | int 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; |