diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.c | 77 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 30 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 69 |
4 files changed, 81 insertions, 96 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index aa824e2c521f..7a08491e208e 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -640,6 +640,73 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans, | |||
640 | } | 640 | } |
641 | 641 | ||
642 | /* | 642 | /* |
643 | * readahead one full node of leaves | ||
644 | */ | ||
645 | static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, | ||
646 | int slot) | ||
647 | { | ||
648 | struct btrfs_node *node; | ||
649 | int i; | ||
650 | u32 nritems; | ||
651 | u64 item_objectid; | ||
652 | u64 blocknr; | ||
653 | u64 search; | ||
654 | u64 cluster_start; | ||
655 | int ret; | ||
656 | int nread = 0; | ||
657 | int direction = path->reada; | ||
658 | struct radix_tree_root found; | ||
659 | unsigned long gang[8]; | ||
660 | struct buffer_head *bh; | ||
661 | |||
662 | if (!path->nodes[1]) | ||
663 | return; | ||
664 | |||
665 | node = btrfs_buffer_node(path->nodes[1]); | ||
666 | search = btrfs_node_blockptr(node, slot); | ||
667 | bh = btrfs_find_tree_block(root, search); | ||
668 | if (bh) { | ||
669 | brelse(bh); | ||
670 | return; | ||
671 | } | ||
672 | |||
673 | init_bit_radix(&found); | ||
674 | nritems = btrfs_header_nritems(&node->header); | ||
675 | for (i = slot; i < nritems; i++) { | ||
676 | item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key); | ||
677 | blocknr = btrfs_node_blockptr(node, i); | ||
678 | set_radix_bit(&found, blocknr); | ||
679 | } | ||
680 | if (direction > 0) { | ||
681 | cluster_start = search - 4; | ||
682 | if (cluster_start > search) | ||
683 | cluster_start = 0; | ||
684 | } else | ||
685 | cluster_start = search + 4; | ||
686 | while(1) { | ||
687 | ret = find_first_radix_bit(&found, gang, 0, ARRAY_SIZE(gang)); | ||
688 | if (!ret) | ||
689 | break; | ||
690 | for (i = 0; i < ret; i++) { | ||
691 | blocknr = gang[i]; | ||
692 | clear_radix_bit(&found, blocknr); | ||
693 | if (nread > 64) | ||
694 | continue; | ||
695 | if (direction > 0 && cluster_start <= blocknr && | ||
696 | cluster_start + 8 > blocknr) { | ||
697 | cluster_start = blocknr; | ||
698 | readahead_tree_block(root, blocknr); | ||
699 | nread++; | ||
700 | } else if (direction < 0 && cluster_start >= blocknr && | ||
701 | blocknr + 8 > cluster_start) { | ||
702 | cluster_start = blocknr; | ||
703 | readahead_tree_block(root, blocknr); | ||
704 | nread++; | ||
705 | } | ||
706 | } | ||
707 | } | ||
708 | } | ||
709 | /* | ||
643 | * look for key in the tree. path is filled in with nodes along the way | 710 | * look for key in the tree. path is filled in with nodes along the way |
644 | * if key is found, we return zero and you can find the item in the leaf | 711 | * if key is found, we return zero and you can find the item in the leaf |
645 | * level of the path (level 0) | 712 | * level of the path (level 0) |
@@ -660,9 +727,11 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
660 | struct buffer_head *cow_buf; | 727 | struct buffer_head *cow_buf; |
661 | struct btrfs_node *c; | 728 | struct btrfs_node *c; |
662 | struct btrfs_root_item *root_item = &root->root_item; | 729 | struct btrfs_root_item *root_item = &root->root_item; |
730 | u64 blocknr; | ||
663 | int slot; | 731 | int slot; |
664 | int ret; | 732 | int ret; |
665 | int level; | 733 | int level; |
734 | int should_reada = p->reada; | ||
666 | u8 lowest_level = 0; | 735 | u8 lowest_level = 0; |
667 | 736 | ||
668 | if (btrfs_root_refs(root_item) == 0 && root->ref_cows) { | 737 | if (btrfs_root_refs(root_item) == 0 && root->ref_cows) { |
@@ -728,7 +797,11 @@ again: | |||
728 | /* this is only true while dropping a snapshot */ | 797 | /* this is only true while dropping a snapshot */ |
729 | if (level == lowest_level) | 798 | if (level == lowest_level) |
730 | break; | 799 | break; |
800 | blocknr = btrfs_node_blockptr(c, slot); | ||
801 | if (level == 1 && should_reada) | ||
802 | reada_for_search(root, p, slot); | ||
731 | b = read_tree_block(root, btrfs_node_blockptr(c, slot)); | 803 | b = read_tree_block(root, btrfs_node_blockptr(c, slot)); |
804 | |||
732 | } else { | 805 | } else { |
733 | struct btrfs_leaf *l = (struct btrfs_leaf *)c; | 806 | struct btrfs_leaf *l = (struct btrfs_leaf *)c; |
734 | p->slots[level] = slot; | 807 | p->slots[level] = slot; |
@@ -1915,6 +1988,8 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) | |||
1915 | blocknr = btrfs_node_blockptr(c_node, slot); | 1988 | blocknr = btrfs_node_blockptr(c_node, slot); |
1916 | if (next) | 1989 | if (next) |
1917 | btrfs_block_release(root, next); | 1990 | btrfs_block_release(root, next); |
1991 | if (level == 1 && path->reada) | ||
1992 | reada_for_search(root, path, slot); | ||
1918 | next = read_tree_block(root, blocknr); | 1993 | next = read_tree_block(root, blocknr); |
1919 | break; | 1994 | break; |
1920 | } | 1995 | } |
@@ -1927,6 +2002,8 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) | |||
1927 | path->slots[level] = 0; | 2002 | path->slots[level] = 0; |
1928 | if (!level) | 2003 | if (!level) |
1929 | break; | 2004 | break; |
2005 | if (level == 1 && path->reada) | ||
2006 | reada_for_search(root, path, slot); | ||
1930 | next = read_tree_block(root, | 2007 | next = read_tree_block(root, |
1931 | btrfs_node_blockptr(btrfs_buffer_node(next), 0)); | 2008 | btrfs_node_blockptr(btrfs_buffer_node(next), 0)); |
1932 | } | 2009 | } |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 73c2e75a136d..c5a18d5d7f7c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -177,6 +177,7 @@ struct btrfs_node { | |||
177 | struct btrfs_path { | 177 | struct btrfs_path { |
178 | struct buffer_head *nodes[BTRFS_MAX_LEVEL]; | 178 | struct buffer_head *nodes[BTRFS_MAX_LEVEL]; |
179 | int slots[BTRFS_MAX_LEVEL]; | 179 | int slots[BTRFS_MAX_LEVEL]; |
180 | int reada; | ||
180 | }; | 181 | }; |
181 | 182 | ||
182 | /* | 183 | /* |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 9455974dabea..5d4d5d8db8ef 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -32,33 +32,6 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct | |||
32 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct | 32 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct |
33 | btrfs_root *extent_root); | 33 | btrfs_root *extent_root); |
34 | 34 | ||
35 | static void reada_extent_leaves(struct btrfs_root *root, | ||
36 | struct btrfs_path *path, u64 limit) | ||
37 | { | ||
38 | struct btrfs_node *node; | ||
39 | int i; | ||
40 | int nritems; | ||
41 | u64 item_objectid; | ||
42 | u64 blocknr; | ||
43 | int slot; | ||
44 | int ret; | ||
45 | |||
46 | if (!path->nodes[1]) | ||
47 | return; | ||
48 | node = btrfs_buffer_node(path->nodes[1]); | ||
49 | slot = path->slots[1] + 1; | ||
50 | nritems = btrfs_header_nritems(&node->header); | ||
51 | for (i = slot; i < nritems && i < slot + 8; i++) { | ||
52 | item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key); | ||
53 | if (item_objectid > limit) | ||
54 | break; | ||
55 | blocknr = btrfs_node_blockptr(node, i); | ||
56 | ret = readahead_tree_block(root, blocknr); | ||
57 | if (ret) | ||
58 | break; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | static int cache_block_group(struct btrfs_root *root, | 35 | static int cache_block_group(struct btrfs_root *root, |
63 | struct btrfs_block_group_cache *block_group) | 36 | struct btrfs_block_group_cache *block_group) |
64 | { | 37 | { |
@@ -84,6 +57,7 @@ static int cache_block_group(struct btrfs_root *root, | |||
84 | path = btrfs_alloc_path(); | 57 | path = btrfs_alloc_path(); |
85 | if (!path) | 58 | if (!path) |
86 | return -ENOMEM; | 59 | return -ENOMEM; |
60 | path->reada = 1; | ||
87 | key.objectid = block_group->key.objectid; | 61 | key.objectid = block_group->key.objectid; |
88 | key.flags = 0; | 62 | key.flags = 0; |
89 | key.offset = 0; | 63 | key.offset = 0; |
@@ -94,12 +68,10 @@ static int cache_block_group(struct btrfs_root *root, | |||
94 | if (ret && path->slots[0] > 0) | 68 | if (ret && path->slots[0] > 0) |
95 | path->slots[0]--; | 69 | path->slots[0]--; |
96 | limit = block_group->key.objectid + block_group->key.offset; | 70 | limit = block_group->key.objectid + block_group->key.offset; |
97 | reada_extent_leaves(root, path, limit); | ||
98 | while(1) { | 71 | while(1) { |
99 | leaf = btrfs_buffer_leaf(path->nodes[0]); | 72 | leaf = btrfs_buffer_leaf(path->nodes[0]); |
100 | slot = path->slots[0]; | 73 | slot = path->slots[0]; |
101 | if (slot >= btrfs_header_nritems(&leaf->header)) { | 74 | if (slot >= btrfs_header_nritems(&leaf->header)) { |
102 | reada_extent_leaves(root, path, limit); | ||
103 | ret = btrfs_next_leaf(root, path); | 75 | ret = btrfs_next_leaf(root, path); |
104 | if (ret < 0) | 76 | if (ret < 0) |
105 | goto err; | 77 | goto err; |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index fa9c531c86b7..3889032fc449 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -375,40 +375,6 @@ static int btrfs_free_inode(struct btrfs_trans_handle *trans, | |||
375 | } | 375 | } |
376 | 376 | ||
377 | /* | 377 | /* |
378 | * truncates go from a high offset to a low offset. So, walk | ||
379 | * from hi to lo in the node and issue readas. Stop when you find | ||
380 | * keys from a different objectid | ||
381 | */ | ||
382 | static void reada_truncate(struct btrfs_root *root, struct btrfs_path *path, | ||
383 | u64 objectid) | ||
384 | { | ||
385 | struct btrfs_node *node; | ||
386 | int i; | ||
387 | int nritems; | ||
388 | u64 item_objectid; | ||
389 | u64 blocknr; | ||
390 | int slot; | ||
391 | int ret; | ||
392 | |||
393 | if (!path->nodes[1]) | ||
394 | return; | ||
395 | node = btrfs_buffer_node(path->nodes[1]); | ||
396 | slot = path->slots[1]; | ||
397 | if (slot == 0) | ||
398 | return; | ||
399 | nritems = btrfs_header_nritems(&node->header); | ||
400 | for (i = slot - 1; i >= 0; i--) { | ||
401 | item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key); | ||
402 | if (item_objectid != objectid) | ||
403 | break; | ||
404 | blocknr = btrfs_node_blockptr(node, i); | ||
405 | ret = readahead_tree_block(root, blocknr); | ||
406 | if (ret) | ||
407 | break; | ||
408 | } | ||
409 | } | ||
410 | |||
411 | /* | ||
412 | * this can truncate away extent items, csum items and directory items. | 378 | * this can truncate away extent items, csum items and directory items. |
413 | * It starts at a high offset and removes keys until it can't find | 379 | * It starts at a high offset and removes keys until it can't find |
414 | * any higher than i_size. | 380 | * any higher than i_size. |
@@ -434,6 +400,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
434 | int del_item; | 400 | int del_item; |
435 | 401 | ||
436 | path = btrfs_alloc_path(); | 402 | path = btrfs_alloc_path(); |
403 | path->reada = -1; | ||
437 | BUG_ON(!path); | 404 | BUG_ON(!path); |
438 | /* FIXME, add redo link to tree so we don't leak on crash */ | 405 | /* FIXME, add redo link to tree so we don't leak on crash */ |
439 | key.objectid = inode->i_ino; | 406 | key.objectid = inode->i_ino; |
@@ -450,7 +417,6 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
450 | BUG_ON(path->slots[0] == 0); | 417 | BUG_ON(path->slots[0] == 0); |
451 | path->slots[0]--; | 418 | path->slots[0]--; |
452 | } | 419 | } |
453 | reada_truncate(root, path, inode->i_ino); | ||
454 | leaf = btrfs_buffer_leaf(path->nodes[0]); | 420 | leaf = btrfs_buffer_leaf(path->nodes[0]); |
455 | found_key = &leaf->items[path->slots[0]].key; | 421 | found_key = &leaf->items[path->slots[0]].key; |
456 | found_type = btrfs_disk_key_type(found_key); | 422 | found_type = btrfs_disk_key_type(found_key); |
@@ -827,36 +793,6 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
827 | return d_splice_alias(inode, dentry); | 793 | return d_splice_alias(inode, dentry); |
828 | } | 794 | } |
829 | 795 | ||
830 | /* | ||
831 | * readahead one full node of leaves as long as their keys include | ||
832 | * the objectid supplied | ||
833 | */ | ||
834 | static void reada_leaves(struct btrfs_root *root, struct btrfs_path *path, | ||
835 | u64 objectid) | ||
836 | { | ||
837 | struct btrfs_node *node; | ||
838 | int i; | ||
839 | u32 nritems; | ||
840 | u64 item_objectid; | ||
841 | u64 blocknr; | ||
842 | int slot; | ||
843 | int ret; | ||
844 | |||
845 | if (!path->nodes[1]) | ||
846 | return; | ||
847 | node = btrfs_buffer_node(path->nodes[1]); | ||
848 | slot = path->slots[1]; | ||
849 | nritems = btrfs_header_nritems(&node->header); | ||
850 | for (i = slot + 1; i < nritems; i++) { | ||
851 | item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key); | ||
852 | if (item_objectid != objectid) | ||
853 | break; | ||
854 | blocknr = btrfs_node_blockptr(node, i); | ||
855 | ret = readahead_tree_block(root, blocknr); | ||
856 | if (ret) | ||
857 | break; | ||
858 | } | ||
859 | } | ||
860 | static unsigned char btrfs_filetype_table[] = { | 796 | static unsigned char btrfs_filetype_table[] = { |
861 | DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK | 797 | DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK |
862 | }; | 798 | }; |
@@ -890,18 +826,17 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
890 | btrfs_set_key_type(&key, key_type); | 826 | btrfs_set_key_type(&key, key_type); |
891 | key.offset = filp->f_pos; | 827 | key.offset = filp->f_pos; |
892 | path = btrfs_alloc_path(); | 828 | path = btrfs_alloc_path(); |
829 | path->reada = 1; | ||
893 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 830 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
894 | if (ret < 0) | 831 | if (ret < 0) |
895 | goto err; | 832 | goto err; |
896 | advance = 0; | 833 | advance = 0; |
897 | reada_leaves(root, path, inode->i_ino); | ||
898 | while(1) { | 834 | while(1) { |
899 | leaf = btrfs_buffer_leaf(path->nodes[0]); | 835 | leaf = btrfs_buffer_leaf(path->nodes[0]); |
900 | nritems = btrfs_header_nritems(&leaf->header); | 836 | nritems = btrfs_header_nritems(&leaf->header); |
901 | slot = path->slots[0]; | 837 | slot = path->slots[0]; |
902 | if (advance || slot >= nritems) { | 838 | if (advance || slot >= nritems) { |
903 | if (slot >= nritems -1) { | 839 | if (slot >= nritems -1) { |
904 | reada_leaves(root, path, inode->i_ino); | ||
905 | ret = btrfs_next_leaf(root, path); | 840 | ret = btrfs_next_leaf(root, path); |
906 | if (ret) | 841 | if (ret) |
907 | break; | 842 | break; |