diff options
author | Chris Mason <chris.mason@fusionio.com> | 2012-10-25 15:53:10 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2012-10-25 15:53:10 -0400 |
commit | c657c3ef1adb2585ed7d2a6db73d0002926a6726 (patch) | |
tree | 5a53c8a58d5be5986d72fd2da8613aac118cf15c /fs/btrfs | |
parent | be6aef604920406b348acf3be6e6e8db55696386 (diff) | |
parent | 01763a2e37425ae3f37a3dc051e0703fdade5956 (diff) |
Merge branch 'for-chris-fixed' of git://git.jan-o-sch.net/btrfs-unstable
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/backref.c | 4 | ||||
-rw-r--r-- | fs/btrfs/ctree.c | 68 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 1 |
3 files changed, 55 insertions, 18 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index b8b69266393a..208d8aa5b07e 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c | |||
@@ -283,9 +283,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | |||
283 | goto out; | 283 | goto out; |
284 | } | 284 | } |
285 | 285 | ||
286 | rcu_read_lock(); | 286 | root_level = btrfs_old_root_level(root, time_seq); |
287 | root_level = btrfs_header_level(root->node); | ||
288 | rcu_read_unlock(); | ||
289 | 287 | ||
290 | if (root_level + 1 == level) | 288 | if (root_level + 1 == level) |
291 | goto out; | 289 | goto out; |
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index b33436211000..eba44b076829 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -596,6 +596,11 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info, | |||
596 | if (tree_mod_dont_log(fs_info, eb)) | 596 | if (tree_mod_dont_log(fs_info, eb)) |
597 | return 0; | 597 | return 0; |
598 | 598 | ||
599 | /* | ||
600 | * When we override something during the move, we log these removals. | ||
601 | * This can only happen when we move towards the beginning of the | ||
602 | * buffer, i.e. dst_slot < src_slot. | ||
603 | */ | ||
599 | for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { | 604 | for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { |
600 | ret = tree_mod_log_insert_key_locked(fs_info, eb, i + dst_slot, | 605 | ret = tree_mod_log_insert_key_locked(fs_info, eb, i + dst_slot, |
601 | MOD_LOG_KEY_REMOVE_WHILE_MOVING); | 606 | MOD_LOG_KEY_REMOVE_WHILE_MOVING); |
@@ -647,8 +652,6 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info, | |||
647 | if (tree_mod_dont_log(fs_info, NULL)) | 652 | if (tree_mod_dont_log(fs_info, NULL)) |
648 | return 0; | 653 | return 0; |
649 | 654 | ||
650 | __tree_mod_log_free_eb(fs_info, old_root); | ||
651 | |||
652 | ret = tree_mod_alloc(fs_info, flags, &tm); | 655 | ret = tree_mod_alloc(fs_info, flags, &tm); |
653 | if (ret < 0) | 656 | if (ret < 0) |
654 | goto out; | 657 | goto out; |
@@ -926,12 +929,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, | |||
926 | ret = btrfs_dec_ref(trans, root, buf, 1, 1); | 929 | ret = btrfs_dec_ref(trans, root, buf, 1, 1); |
927 | BUG_ON(ret); /* -ENOMEM */ | 930 | BUG_ON(ret); /* -ENOMEM */ |
928 | } | 931 | } |
929 | /* | 932 | tree_mod_log_free_eb(root->fs_info, buf); |
930 | * don't log freeing in case we're freeing the root node, this | ||
931 | * is done by tree_mod_log_set_root_pointer later | ||
932 | */ | ||
933 | if (buf != root->node && btrfs_header_level(buf) != 0) | ||
934 | tree_mod_log_free_eb(root->fs_info, buf); | ||
935 | clean_tree_block(trans, root, buf); | 933 | clean_tree_block(trans, root, buf); |
936 | *last_ref = 1; | 934 | *last_ref = 1; |
937 | } | 935 | } |
@@ -1225,6 +1223,8 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, | |||
1225 | free_extent_buffer(eb); | 1223 | free_extent_buffer(eb); |
1226 | 1224 | ||
1227 | __tree_mod_log_rewind(eb_rewin, time_seq, tm); | 1225 | __tree_mod_log_rewind(eb_rewin, time_seq, tm); |
1226 | WARN_ON(btrfs_header_nritems(eb_rewin) > | ||
1227 | BTRFS_NODEPTRS_PER_BLOCK(fs_info->fs_root)); | ||
1228 | 1228 | ||
1229 | return eb_rewin; | 1229 | return eb_rewin; |
1230 | } | 1230 | } |
@@ -1244,6 +1244,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq) | |||
1244 | struct tree_mod_root *old_root = NULL; | 1244 | struct tree_mod_root *old_root = NULL; |
1245 | u64 old_generation = 0; | 1245 | u64 old_generation = 0; |
1246 | u64 logical; | 1246 | u64 logical; |
1247 | u32 blocksize; | ||
1247 | 1248 | ||
1248 | eb = btrfs_read_lock_root_node(root); | 1249 | eb = btrfs_read_lock_root_node(root); |
1249 | tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq); | 1250 | tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq); |
@@ -1259,14 +1260,31 @@ get_old_root(struct btrfs_root *root, u64 time_seq) | |||
1259 | } | 1260 | } |
1260 | 1261 | ||
1261 | tm = tree_mod_log_search(root->fs_info, logical, time_seq); | 1262 | tm = tree_mod_log_search(root->fs_info, logical, time_seq); |
1262 | if (old_root) | 1263 | if (old_root && tm && tm->op != MOD_LOG_KEY_REMOVE_WHILE_FREEING) { |
1264 | btrfs_tree_read_unlock(root->node); | ||
1265 | free_extent_buffer(root->node); | ||
1266 | blocksize = btrfs_level_size(root, old_root->level); | ||
1267 | eb = read_tree_block(root, logical, blocksize, 0); | ||
1268 | if (!eb) { | ||
1269 | pr_warn("btrfs: failed to read tree block %llu from get_old_root\n", | ||
1270 | logical); | ||
1271 | WARN_ON(1); | ||
1272 | } else { | ||
1273 | eb = btrfs_clone_extent_buffer(eb); | ||
1274 | } | ||
1275 | } else if (old_root) { | ||
1276 | btrfs_tree_read_unlock(root->node); | ||
1277 | free_extent_buffer(root->node); | ||
1263 | eb = alloc_dummy_extent_buffer(logical, root->nodesize); | 1278 | eb = alloc_dummy_extent_buffer(logical, root->nodesize); |
1264 | else | 1279 | } else { |
1265 | eb = btrfs_clone_extent_buffer(root->node); | 1280 | eb = btrfs_clone_extent_buffer(root->node); |
1266 | btrfs_tree_read_unlock(root->node); | 1281 | btrfs_tree_read_unlock(root->node); |
1267 | free_extent_buffer(root->node); | 1282 | free_extent_buffer(root->node); |
1283 | } | ||
1284 | |||
1268 | if (!eb) | 1285 | if (!eb) |
1269 | return NULL; | 1286 | return NULL; |
1287 | extent_buffer_get(eb); | ||
1270 | btrfs_tree_read_lock(eb); | 1288 | btrfs_tree_read_lock(eb); |
1271 | if (old_root) { | 1289 | if (old_root) { |
1272 | btrfs_set_header_bytenr(eb, eb->start); | 1290 | btrfs_set_header_bytenr(eb, eb->start); |
@@ -1279,11 +1297,28 @@ get_old_root(struct btrfs_root *root, u64 time_seq) | |||
1279 | __tree_mod_log_rewind(eb, time_seq, tm); | 1297 | __tree_mod_log_rewind(eb, time_seq, tm); |
1280 | else | 1298 | else |
1281 | WARN_ON(btrfs_header_level(eb) != 0); | 1299 | WARN_ON(btrfs_header_level(eb) != 0); |
1282 | extent_buffer_get(eb); | 1300 | WARN_ON(btrfs_header_nritems(eb) > BTRFS_NODEPTRS_PER_BLOCK(root)); |
1283 | 1301 | ||
1284 | return eb; | 1302 | return eb; |
1285 | } | 1303 | } |
1286 | 1304 | ||
1305 | int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq) | ||
1306 | { | ||
1307 | struct tree_mod_elem *tm; | ||
1308 | int level; | ||
1309 | |||
1310 | tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq); | ||
1311 | if (tm && tm->op == MOD_LOG_ROOT_REPLACE) { | ||
1312 | level = tm->old_root.level; | ||
1313 | } else { | ||
1314 | rcu_read_lock(); | ||
1315 | level = btrfs_header_level(root->node); | ||
1316 | rcu_read_unlock(); | ||
1317 | } | ||
1318 | |||
1319 | return level; | ||
1320 | } | ||
1321 | |||
1287 | static inline int should_cow_block(struct btrfs_trans_handle *trans, | 1322 | static inline int should_cow_block(struct btrfs_trans_handle *trans, |
1288 | struct btrfs_root *root, | 1323 | struct btrfs_root *root, |
1289 | struct extent_buffer *buf) | 1324 | struct extent_buffer *buf) |
@@ -1725,6 +1760,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
1725 | goto enospc; | 1760 | goto enospc; |
1726 | } | 1761 | } |
1727 | 1762 | ||
1763 | tree_mod_log_free_eb(root->fs_info, root->node); | ||
1728 | tree_mod_log_set_root_pointer(root, child); | 1764 | tree_mod_log_set_root_pointer(root, child); |
1729 | rcu_assign_pointer(root->node, child); | 1765 | rcu_assign_pointer(root->node, child); |
1730 | 1766 | ||
@@ -2970,8 +3006,10 @@ static int push_node_left(struct btrfs_trans_handle *trans, | |||
2970 | push_items * sizeof(struct btrfs_key_ptr)); | 3006 | push_items * sizeof(struct btrfs_key_ptr)); |
2971 | 3007 | ||
2972 | if (push_items < src_nritems) { | 3008 | if (push_items < src_nritems) { |
2973 | tree_mod_log_eb_move(root->fs_info, src, 0, push_items, | 3009 | /* |
2974 | src_nritems - push_items); | 3010 | * don't call tree_mod_log_eb_move here, key removal was already |
3011 | * fully logged by tree_mod_log_eb_copy above. | ||
3012 | */ | ||
2975 | memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0), | 3013 | memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0), |
2976 | btrfs_node_key_ptr_offset(push_items), | 3014 | btrfs_node_key_ptr_offset(push_items), |
2977 | (src_nritems - push_items) * | 3015 | (src_nritems - push_items) * |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 8a92ab1632a2..2ce1135400cf 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -3120,6 +3120,7 @@ static inline u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info) | |||
3120 | { | 3120 | { |
3121 | return atomic_inc_return(&fs_info->tree_mod_seq); | 3121 | return atomic_inc_return(&fs_info->tree_mod_seq); |
3122 | } | 3122 | } |
3123 | int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq); | ||
3123 | 3124 | ||
3124 | /* root-item.c */ | 3125 | /* root-item.c */ |
3125 | int btrfs_find_root_ref(struct btrfs_root *tree_root, | 3126 | int btrfs_find_root_ref(struct btrfs_root *tree_root, |