diff options
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 60 |
1 files changed, 35 insertions, 25 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 15cbc2bf4ff0..8206b3900587 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -1024,11 +1024,18 @@ __tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info, | |||
1024 | if (!looped && !tm) | 1024 | if (!looped && !tm) |
1025 | return 0; | 1025 | return 0; |
1026 | /* | 1026 | /* |
1027 | * we must have key remove operations in the log before the | 1027 | * if there are no tree operation for the oldest root, we simply |
1028 | * replace operation. | 1028 | * return it. this should only happen if that (old) root is at |
1029 | * level 0. | ||
1029 | */ | 1030 | */ |
1030 | BUG_ON(!tm); | 1031 | if (!tm) |
1032 | break; | ||
1031 | 1033 | ||
1034 | /* | ||
1035 | * if there's an operation that's not a root replacement, we | ||
1036 | * found the oldest version of our root. normally, we'll find a | ||
1037 | * MOD_LOG_KEY_REMOVE_WHILE_FREEING operation here. | ||
1038 | */ | ||
1032 | if (tm->op != MOD_LOG_ROOT_REPLACE) | 1039 | if (tm->op != MOD_LOG_ROOT_REPLACE) |
1033 | break; | 1040 | break; |
1034 | 1041 | ||
@@ -1087,11 +1094,7 @@ __tree_mod_log_rewind(struct extent_buffer *eb, u64 time_seq, | |||
1087 | tm->generation); | 1094 | tm->generation); |
1088 | break; | 1095 | break; |
1089 | case MOD_LOG_KEY_ADD: | 1096 | case MOD_LOG_KEY_ADD: |
1090 | if (tm->slot != n - 1) { | 1097 | /* if a move operation is needed it's in the log */ |
1091 | o_dst = btrfs_node_key_ptr_offset(tm->slot); | ||
1092 | o_src = btrfs_node_key_ptr_offset(tm->slot + 1); | ||
1093 | memmove_extent_buffer(eb, o_dst, o_src, p_size); | ||
1094 | } | ||
1095 | n--; | 1098 | n--; |
1096 | break; | 1099 | break; |
1097 | case MOD_LOG_MOVE_KEYS: | 1100 | case MOD_LOG_MOVE_KEYS: |
@@ -1192,16 +1195,8 @@ get_old_root(struct btrfs_root *root, u64 time_seq) | |||
1192 | } | 1195 | } |
1193 | 1196 | ||
1194 | tm = tree_mod_log_search(root->fs_info, logical, time_seq); | 1197 | tm = tree_mod_log_search(root->fs_info, logical, time_seq); |
1195 | /* | ||
1196 | * there was an item in the log when __tree_mod_log_oldest_root | ||
1197 | * returned. this one must not go away, because the time_seq passed to | ||
1198 | * us must be blocking its removal. | ||
1199 | */ | ||
1200 | BUG_ON(!tm); | ||
1201 | |||
1202 | if (old_root) | 1198 | if (old_root) |
1203 | eb = alloc_dummy_extent_buffer(tm->index << PAGE_CACHE_SHIFT, | 1199 | eb = alloc_dummy_extent_buffer(logical, root->nodesize); |
1204 | root->nodesize); | ||
1205 | else | 1200 | else |
1206 | eb = btrfs_clone_extent_buffer(root->node); | 1201 | eb = btrfs_clone_extent_buffer(root->node); |
1207 | btrfs_tree_read_unlock(root->node); | 1202 | btrfs_tree_read_unlock(root->node); |
@@ -1216,7 +1211,10 @@ get_old_root(struct btrfs_root *root, u64 time_seq) | |||
1216 | btrfs_set_header_level(eb, old_root->level); | 1211 | btrfs_set_header_level(eb, old_root->level); |
1217 | btrfs_set_header_generation(eb, old_generation); | 1212 | btrfs_set_header_generation(eb, old_generation); |
1218 | } | 1213 | } |
1219 | __tree_mod_log_rewind(eb, time_seq, tm); | 1214 | if (tm) |
1215 | __tree_mod_log_rewind(eb, time_seq, tm); | ||
1216 | else | ||
1217 | WARN_ON(btrfs_header_level(eb) != 0); | ||
1220 | extent_buffer_get(eb); | 1218 | extent_buffer_get(eb); |
1221 | 1219 | ||
1222 | return eb; | 1220 | return eb; |
@@ -2995,7 +2993,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans, | |||
2995 | static void insert_ptr(struct btrfs_trans_handle *trans, | 2993 | static void insert_ptr(struct btrfs_trans_handle *trans, |
2996 | struct btrfs_root *root, struct btrfs_path *path, | 2994 | struct btrfs_root *root, struct btrfs_path *path, |
2997 | struct btrfs_disk_key *key, u64 bytenr, | 2995 | struct btrfs_disk_key *key, u64 bytenr, |
2998 | int slot, int level, int tree_mod_log) | 2996 | int slot, int level) |
2999 | { | 2997 | { |
3000 | struct extent_buffer *lower; | 2998 | struct extent_buffer *lower; |
3001 | int nritems; | 2999 | int nritems; |
@@ -3008,7 +3006,7 @@ static void insert_ptr(struct btrfs_trans_handle *trans, | |||
3008 | BUG_ON(slot > nritems); | 3006 | BUG_ON(slot > nritems); |
3009 | BUG_ON(nritems == BTRFS_NODEPTRS_PER_BLOCK(root)); | 3007 | BUG_ON(nritems == BTRFS_NODEPTRS_PER_BLOCK(root)); |
3010 | if (slot != nritems) { | 3008 | if (slot != nritems) { |
3011 | if (tree_mod_log && level) | 3009 | if (level) |
3012 | tree_mod_log_eb_move(root->fs_info, lower, slot + 1, | 3010 | tree_mod_log_eb_move(root->fs_info, lower, slot + 1, |
3013 | slot, nritems - slot); | 3011 | slot, nritems - slot); |
3014 | memmove_extent_buffer(lower, | 3012 | memmove_extent_buffer(lower, |
@@ -3016,7 +3014,7 @@ static void insert_ptr(struct btrfs_trans_handle *trans, | |||
3016 | btrfs_node_key_ptr_offset(slot), | 3014 | btrfs_node_key_ptr_offset(slot), |
3017 | (nritems - slot) * sizeof(struct btrfs_key_ptr)); | 3015 | (nritems - slot) * sizeof(struct btrfs_key_ptr)); |
3018 | } | 3016 | } |
3019 | if (tree_mod_log && level) { | 3017 | if (level) { |
3020 | ret = tree_mod_log_insert_key(root->fs_info, lower, slot, | 3018 | ret = tree_mod_log_insert_key(root->fs_info, lower, slot, |
3021 | MOD_LOG_KEY_ADD); | 3019 | MOD_LOG_KEY_ADD); |
3022 | BUG_ON(ret < 0); | 3020 | BUG_ON(ret < 0); |
@@ -3104,7 +3102,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans, | |||
3104 | btrfs_mark_buffer_dirty(split); | 3102 | btrfs_mark_buffer_dirty(split); |
3105 | 3103 | ||
3106 | insert_ptr(trans, root, path, &disk_key, split->start, | 3104 | insert_ptr(trans, root, path, &disk_key, split->start, |
3107 | path->slots[level + 1] + 1, level + 1, 1); | 3105 | path->slots[level + 1] + 1, level + 1); |
3108 | 3106 | ||
3109 | if (path->slots[level] >= mid) { | 3107 | if (path->slots[level] >= mid) { |
3110 | path->slots[level] -= mid; | 3108 | path->slots[level] -= mid; |
@@ -3641,7 +3639,7 @@ static noinline void copy_for_split(struct btrfs_trans_handle *trans, | |||
3641 | btrfs_set_header_nritems(l, mid); | 3639 | btrfs_set_header_nritems(l, mid); |
3642 | btrfs_item_key(right, &disk_key, 0); | 3640 | btrfs_item_key(right, &disk_key, 0); |
3643 | insert_ptr(trans, root, path, &disk_key, right->start, | 3641 | insert_ptr(trans, root, path, &disk_key, right->start, |
3644 | path->slots[1] + 1, 1, 0); | 3642 | path->slots[1] + 1, 1); |
3645 | 3643 | ||
3646 | btrfs_mark_buffer_dirty(right); | 3644 | btrfs_mark_buffer_dirty(right); |
3647 | btrfs_mark_buffer_dirty(l); | 3645 | btrfs_mark_buffer_dirty(l); |
@@ -3848,7 +3846,7 @@ again: | |||
3848 | if (mid <= slot) { | 3846 | if (mid <= slot) { |
3849 | btrfs_set_header_nritems(right, 0); | 3847 | btrfs_set_header_nritems(right, 0); |
3850 | insert_ptr(trans, root, path, &disk_key, right->start, | 3848 | insert_ptr(trans, root, path, &disk_key, right->start, |
3851 | path->slots[1] + 1, 1, 0); | 3849 | path->slots[1] + 1, 1); |
3852 | btrfs_tree_unlock(path->nodes[0]); | 3850 | btrfs_tree_unlock(path->nodes[0]); |
3853 | free_extent_buffer(path->nodes[0]); | 3851 | free_extent_buffer(path->nodes[0]); |
3854 | path->nodes[0] = right; | 3852 | path->nodes[0] = right; |
@@ -3857,7 +3855,7 @@ again: | |||
3857 | } else { | 3855 | } else { |
3858 | btrfs_set_header_nritems(right, 0); | 3856 | btrfs_set_header_nritems(right, 0); |
3859 | insert_ptr(trans, root, path, &disk_key, right->start, | 3857 | insert_ptr(trans, root, path, &disk_key, right->start, |
3860 | path->slots[1], 1, 0); | 3858 | path->slots[1], 1); |
3861 | btrfs_tree_unlock(path->nodes[0]); | 3859 | btrfs_tree_unlock(path->nodes[0]); |
3862 | free_extent_buffer(path->nodes[0]); | 3860 | free_extent_buffer(path->nodes[0]); |
3863 | path->nodes[0] = right; | 3861 | path->nodes[0] = right; |
@@ -5121,6 +5119,18 @@ again: | |||
5121 | 5119 | ||
5122 | if (!path->skip_locking) { | 5120 | if (!path->skip_locking) { |
5123 | ret = btrfs_try_tree_read_lock(next); | 5121 | ret = btrfs_try_tree_read_lock(next); |
5122 | if (!ret && time_seq) { | ||
5123 | /* | ||
5124 | * If we don't get the lock, we may be racing | ||
5125 | * with push_leaf_left, holding that lock while | ||
5126 | * itself waiting for the leaf we've currently | ||
5127 | * locked. To solve this situation, we give up | ||
5128 | * on our lock and cycle. | ||
5129 | */ | ||
5130 | btrfs_release_path(path); | ||
5131 | cond_resched(); | ||
5132 | goto again; | ||
5133 | } | ||
5124 | if (!ret) { | 5134 | if (!ret) { |
5125 | btrfs_set_path_blocking(path); | 5135 | btrfs_set_path_blocking(path); |
5126 | btrfs_tree_read_lock(next); | 5136 | btrfs_tree_read_lock(next); |