diff options
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 159 |
1 files changed, 16 insertions, 143 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index b5baff0dccfe..84d7ca1fe0ba 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -147,10 +147,11 @@ noinline void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p) | |||
147 | struct extent_buffer *btrfs_root_node(struct btrfs_root *root) | 147 | struct extent_buffer *btrfs_root_node(struct btrfs_root *root) |
148 | { | 148 | { |
149 | struct extent_buffer *eb; | 149 | struct extent_buffer *eb; |
150 | spin_lock(&root->node_lock); | 150 | |
151 | eb = root->node; | 151 | rcu_read_lock(); |
152 | eb = rcu_dereference(root->node); | ||
152 | extent_buffer_get(eb); | 153 | extent_buffer_get(eb); |
153 | spin_unlock(&root->node_lock); | 154 | rcu_read_unlock(); |
154 | return eb; | 155 | return eb; |
155 | } | 156 | } |
156 | 157 | ||
@@ -165,14 +166,8 @@ struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root) | |||
165 | while (1) { | 166 | while (1) { |
166 | eb = btrfs_root_node(root); | 167 | eb = btrfs_root_node(root); |
167 | btrfs_tree_lock(eb); | 168 | btrfs_tree_lock(eb); |
168 | 169 | if (eb == root->node) | |
169 | spin_lock(&root->node_lock); | ||
170 | if (eb == root->node) { | ||
171 | spin_unlock(&root->node_lock); | ||
172 | break; | 170 | break; |
173 | } | ||
174 | spin_unlock(&root->node_lock); | ||
175 | |||
176 | btrfs_tree_unlock(eb); | 171 | btrfs_tree_unlock(eb); |
177 | free_extent_buffer(eb); | 172 | free_extent_buffer(eb); |
178 | } | 173 | } |
@@ -458,10 +453,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
458 | else | 453 | else |
459 | parent_start = 0; | 454 | parent_start = 0; |
460 | 455 | ||
461 | spin_lock(&root->node_lock); | ||
462 | root->node = cow; | ||
463 | extent_buffer_get(cow); | 456 | extent_buffer_get(cow); |
464 | spin_unlock(&root->node_lock); | 457 | rcu_assign_pointer(root->node, cow); |
465 | 458 | ||
466 | btrfs_free_tree_block(trans, root, buf, parent_start, | 459 | btrfs_free_tree_block(trans, root, buf, parent_start, |
467 | last_ref); | 460 | last_ref); |
@@ -542,6 +535,9 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
542 | 535 | ||
543 | ret = __btrfs_cow_block(trans, root, buf, parent, | 536 | ret = __btrfs_cow_block(trans, root, buf, parent, |
544 | parent_slot, cow_ret, search_start, 0); | 537 | parent_slot, cow_ret, search_start, 0); |
538 | |||
539 | trace_btrfs_cow_block(root, buf, *cow_ret); | ||
540 | |||
545 | return ret; | 541 | return ret; |
546 | } | 542 | } |
547 | 543 | ||
@@ -686,6 +682,8 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, | |||
686 | if (!cur) { | 682 | if (!cur) { |
687 | cur = read_tree_block(root, blocknr, | 683 | cur = read_tree_block(root, blocknr, |
688 | blocksize, gen); | 684 | blocksize, gen); |
685 | if (!cur) | ||
686 | return -EIO; | ||
689 | } else if (!uptodate) { | 687 | } else if (!uptodate) { |
690 | btrfs_read_buffer(cur, gen); | 688 | btrfs_read_buffer(cur, gen); |
691 | } | 689 | } |
@@ -732,122 +730,6 @@ static inline unsigned int leaf_data_end(struct btrfs_root *root, | |||
732 | return btrfs_item_offset_nr(leaf, nr - 1); | 730 | return btrfs_item_offset_nr(leaf, nr - 1); |
733 | } | 731 | } |
734 | 732 | ||
735 | /* | ||
736 | * extra debugging checks to make sure all the items in a key are | ||
737 | * well formed and in the proper order | ||
738 | */ | ||
739 | static int check_node(struct btrfs_root *root, struct btrfs_path *path, | ||
740 | int level) | ||
741 | { | ||
742 | struct extent_buffer *parent = NULL; | ||
743 | struct extent_buffer *node = path->nodes[level]; | ||
744 | struct btrfs_disk_key parent_key; | ||
745 | struct btrfs_disk_key node_key; | ||
746 | int parent_slot; | ||
747 | int slot; | ||
748 | struct btrfs_key cpukey; | ||
749 | u32 nritems = btrfs_header_nritems(node); | ||
750 | |||
751 | if (path->nodes[level + 1]) | ||
752 | parent = path->nodes[level + 1]; | ||
753 | |||
754 | slot = path->slots[level]; | ||
755 | BUG_ON(nritems == 0); | ||
756 | if (parent) { | ||
757 | parent_slot = path->slots[level + 1]; | ||
758 | btrfs_node_key(parent, &parent_key, parent_slot); | ||
759 | btrfs_node_key(node, &node_key, 0); | ||
760 | BUG_ON(memcmp(&parent_key, &node_key, | ||
761 | sizeof(struct btrfs_disk_key))); | ||
762 | BUG_ON(btrfs_node_blockptr(parent, parent_slot) != | ||
763 | btrfs_header_bytenr(node)); | ||
764 | } | ||
765 | BUG_ON(nritems > BTRFS_NODEPTRS_PER_BLOCK(root)); | ||
766 | if (slot != 0) { | ||
767 | btrfs_node_key_to_cpu(node, &cpukey, slot - 1); | ||
768 | btrfs_node_key(node, &node_key, slot); | ||
769 | BUG_ON(comp_keys(&node_key, &cpukey) <= 0); | ||
770 | } | ||
771 | if (slot < nritems - 1) { | ||
772 | btrfs_node_key_to_cpu(node, &cpukey, slot + 1); | ||
773 | btrfs_node_key(node, &node_key, slot); | ||
774 | BUG_ON(comp_keys(&node_key, &cpukey) >= 0); | ||
775 | } | ||
776 | return 0; | ||
777 | } | ||
778 | |||
779 | /* | ||
780 | * extra checking to make sure all the items in a leaf are | ||
781 | * well formed and in the proper order | ||
782 | */ | ||
783 | static int check_leaf(struct btrfs_root *root, struct btrfs_path *path, | ||
784 | int level) | ||
785 | { | ||
786 | struct extent_buffer *leaf = path->nodes[level]; | ||
787 | struct extent_buffer *parent = NULL; | ||
788 | int parent_slot; | ||
789 | struct btrfs_key cpukey; | ||
790 | struct btrfs_disk_key parent_key; | ||
791 | struct btrfs_disk_key leaf_key; | ||
792 | int slot = path->slots[0]; | ||
793 | |||
794 | u32 nritems = btrfs_header_nritems(leaf); | ||
795 | |||
796 | if (path->nodes[level + 1]) | ||
797 | parent = path->nodes[level + 1]; | ||
798 | |||
799 | if (nritems == 0) | ||
800 | return 0; | ||
801 | |||
802 | if (parent) { | ||
803 | parent_slot = path->slots[level + 1]; | ||
804 | btrfs_node_key(parent, &parent_key, parent_slot); | ||
805 | btrfs_item_key(leaf, &leaf_key, 0); | ||
806 | |||
807 | BUG_ON(memcmp(&parent_key, &leaf_key, | ||
808 | sizeof(struct btrfs_disk_key))); | ||
809 | BUG_ON(btrfs_node_blockptr(parent, parent_slot) != | ||
810 | btrfs_header_bytenr(leaf)); | ||
811 | } | ||
812 | if (slot != 0 && slot < nritems - 1) { | ||
813 | btrfs_item_key(leaf, &leaf_key, slot); | ||
814 | btrfs_item_key_to_cpu(leaf, &cpukey, slot - 1); | ||
815 | if (comp_keys(&leaf_key, &cpukey) <= 0) { | ||
816 | btrfs_print_leaf(root, leaf); | ||
817 | printk(KERN_CRIT "slot %d offset bad key\n", slot); | ||
818 | BUG_ON(1); | ||
819 | } | ||
820 | if (btrfs_item_offset_nr(leaf, slot - 1) != | ||
821 | btrfs_item_end_nr(leaf, slot)) { | ||
822 | btrfs_print_leaf(root, leaf); | ||
823 | printk(KERN_CRIT "slot %d offset bad\n", slot); | ||
824 | BUG_ON(1); | ||
825 | } | ||
826 | } | ||
827 | if (slot < nritems - 1) { | ||
828 | btrfs_item_key(leaf, &leaf_key, slot); | ||
829 | btrfs_item_key_to_cpu(leaf, &cpukey, slot + 1); | ||
830 | BUG_ON(comp_keys(&leaf_key, &cpukey) >= 0); | ||
831 | if (btrfs_item_offset_nr(leaf, slot) != | ||
832 | btrfs_item_end_nr(leaf, slot + 1)) { | ||
833 | btrfs_print_leaf(root, leaf); | ||
834 | printk(KERN_CRIT "slot %d offset bad\n", slot); | ||
835 | BUG_ON(1); | ||
836 | } | ||
837 | } | ||
838 | BUG_ON(btrfs_item_offset_nr(leaf, 0) + | ||
839 | btrfs_item_size_nr(leaf, 0) != BTRFS_LEAF_DATA_SIZE(root)); | ||
840 | return 0; | ||
841 | } | ||
842 | |||
843 | static noinline int check_block(struct btrfs_root *root, | ||
844 | struct btrfs_path *path, int level) | ||
845 | { | ||
846 | return 0; | ||
847 | if (level == 0) | ||
848 | return check_leaf(root, path, level); | ||
849 | return check_node(root, path, level); | ||
850 | } | ||
851 | 733 | ||
852 | /* | 734 | /* |
853 | * search for key in the extent_buffer. The items start at offset p, | 735 | * search for key in the extent_buffer. The items start at offset p, |
@@ -1046,9 +928,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
1046 | goto enospc; | 928 | goto enospc; |
1047 | } | 929 | } |
1048 | 930 | ||
1049 | spin_lock(&root->node_lock); | 931 | rcu_assign_pointer(root->node, child); |
1050 | root->node = child; | ||
1051 | spin_unlock(&root->node_lock); | ||
1052 | 932 | ||
1053 | add_root_to_dirty_list(root); | 933 | add_root_to_dirty_list(root); |
1054 | btrfs_tree_unlock(child); | 934 | btrfs_tree_unlock(child); |
@@ -1188,7 +1068,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
1188 | } | 1068 | } |
1189 | } | 1069 | } |
1190 | /* double check we haven't messed things up */ | 1070 | /* double check we haven't messed things up */ |
1191 | check_block(root, path, level); | ||
1192 | if (orig_ptr != | 1071 | if (orig_ptr != |
1193 | btrfs_node_blockptr(path->nodes[level], path->slots[level])) | 1072 | btrfs_node_blockptr(path->nodes[level], path->slots[level])) |
1194 | BUG(); | 1073 | BUG(); |
@@ -1798,12 +1677,6 @@ cow_done: | |||
1798 | if (!cow) | 1677 | if (!cow) |
1799 | btrfs_unlock_up_safe(p, level + 1); | 1678 | btrfs_unlock_up_safe(p, level + 1); |
1800 | 1679 | ||
1801 | ret = check_block(root, p, level); | ||
1802 | if (ret) { | ||
1803 | ret = -1; | ||
1804 | goto done; | ||
1805 | } | ||
1806 | |||
1807 | ret = bin_search(b, key, level, &slot); | 1680 | ret = bin_search(b, key, level, &slot); |
1808 | 1681 | ||
1809 | if (level != 0) { | 1682 | if (level != 0) { |
@@ -2130,10 +2003,8 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans, | |||
2130 | 2003 | ||
2131 | btrfs_mark_buffer_dirty(c); | 2004 | btrfs_mark_buffer_dirty(c); |
2132 | 2005 | ||
2133 | spin_lock(&root->node_lock); | ||
2134 | old = root->node; | 2006 | old = root->node; |
2135 | root->node = c; | 2007 | rcu_assign_pointer(root->node, c); |
2136 | spin_unlock(&root->node_lock); | ||
2137 | 2008 | ||
2138 | /* the super has an extra ref to root->node */ | 2009 | /* the super has an extra ref to root->node */ |
2139 | free_extent_buffer(old); | 2010 | free_extent_buffer(old); |
@@ -3840,7 +3711,8 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root | |||
3840 | unsigned long ptr; | 3711 | unsigned long ptr; |
3841 | 3712 | ||
3842 | path = btrfs_alloc_path(); | 3713 | path = btrfs_alloc_path(); |
3843 | BUG_ON(!path); | 3714 | if (!path) |
3715 | return -ENOMEM; | ||
3844 | ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); | 3716 | ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); |
3845 | if (!ret) { | 3717 | if (!ret) { |
3846 | leaf = path->nodes[0]; | 3718 | leaf = path->nodes[0]; |
@@ -4217,6 +4089,7 @@ find_next_key: | |||
4217 | } | 4089 | } |
4218 | btrfs_set_path_blocking(path); | 4090 | btrfs_set_path_blocking(path); |
4219 | cur = read_node_slot(root, cur, slot); | 4091 | cur = read_node_slot(root, cur, slot); |
4092 | BUG_ON(!cur); | ||
4220 | 4093 | ||
4221 | btrfs_tree_lock(cur); | 4094 | btrfs_tree_lock(cur); |
4222 | 4095 | ||