diff options
author | Jan Schmidt <list.btrfs@jan-o-sch.net> | 2012-05-26 05:43:17 -0400 |
---|---|---|
committer | Jan Schmidt <list.btrfs@jan-o-sch.net> | 2012-05-30 09:17:29 -0400 |
commit | f230475e62f77930e776881deb6e95cfd2226bd4 (patch) | |
tree | bf57ab6531a988d5566138b9a4cf916ecfcbbf3f /fs/btrfs/ctree.c | |
parent | bd989ba359f2acb8bc5f5490e19010fc0a6f8356 (diff) |
Btrfs: put all block modifications into the tree mod log
When running functions that can make changes to the internal trees
(e.g. btrfs_search_slot), we check if somebody may be interested in the
block we're currently modifying. If so, we record our modification to be
able to rewind it later on.
Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 72b9f97e2fdc..07c1a96aa4a8 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -39,6 +39,14 @@ static int balance_node_right(struct btrfs_trans_handle *trans, | |||
39 | struct extent_buffer *src_buf); | 39 | struct extent_buffer *src_buf); |
40 | static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 40 | static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
41 | struct btrfs_path *path, int level, int slot); | 41 | struct btrfs_path *path, int level, int slot); |
42 | static void tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, | ||
43 | struct extent_buffer *eb); | ||
44 | struct extent_buffer *read_old_tree_block(struct btrfs_root *root, u64 bytenr, | ||
45 | u32 blocksize, u64 parent_transid, | ||
46 | u64 time_seq); | ||
47 | struct extent_buffer *btrfs_find_old_tree_block(struct btrfs_root *root, | ||
48 | u64 bytenr, u32 blocksize, | ||
49 | u64 time_seq); | ||
42 | 50 | ||
43 | struct btrfs_path *btrfs_alloc_path(void) | 51 | struct btrfs_path *btrfs_alloc_path(void) |
44 | { | 52 | { |
@@ -816,6 +824,12 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, | |||
816 | ret = btrfs_dec_ref(trans, root, buf, 1, 1); | 824 | ret = btrfs_dec_ref(trans, root, buf, 1, 1); |
817 | BUG_ON(ret); /* -ENOMEM */ | 825 | BUG_ON(ret); /* -ENOMEM */ |
818 | } | 826 | } |
827 | /* | ||
828 | * don't log freeing in case we're freeing the root node, this | ||
829 | * is done by tree_mod_log_set_root_pointer later | ||
830 | */ | ||
831 | if (buf != root->node && btrfs_header_level(buf) != 0) | ||
832 | tree_mod_log_free_eb(root->fs_info, buf); | ||
819 | clean_tree_block(trans, root, buf); | 833 | clean_tree_block(trans, root, buf); |
820 | *last_ref = 1; | 834 | *last_ref = 1; |
821 | } | 835 | } |
@@ -913,6 +927,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
913 | parent_start = 0; | 927 | parent_start = 0; |
914 | 928 | ||
915 | extent_buffer_get(cow); | 929 | extent_buffer_get(cow); |
930 | tree_mod_log_set_root_pointer(root, cow); | ||
916 | rcu_assign_pointer(root->node, cow); | 931 | rcu_assign_pointer(root->node, cow); |
917 | 932 | ||
918 | btrfs_free_tree_block(trans, root, buf, parent_start, | 933 | btrfs_free_tree_block(trans, root, buf, parent_start, |
@@ -926,6 +941,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
926 | parent_start = 0; | 941 | parent_start = 0; |
927 | 942 | ||
928 | WARN_ON(trans->transid != btrfs_header_generation(parent)); | 943 | WARN_ON(trans->transid != btrfs_header_generation(parent)); |
944 | tree_mod_log_insert_key(root->fs_info, parent, parent_slot, | ||
945 | MOD_LOG_KEY_REPLACE); | ||
929 | btrfs_set_node_blockptr(parent, parent_slot, | 946 | btrfs_set_node_blockptr(parent, parent_slot, |
930 | cow->start); | 947 | cow->start); |
931 | btrfs_set_node_ptr_generation(parent, parent_slot, | 948 | btrfs_set_node_ptr_generation(parent, parent_slot, |
@@ -1381,6 +1398,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
1381 | goto enospc; | 1398 | goto enospc; |
1382 | } | 1399 | } |
1383 | 1400 | ||
1401 | tree_mod_log_set_root_pointer(root, child); | ||
1384 | rcu_assign_pointer(root->node, child); | 1402 | rcu_assign_pointer(root->node, child); |
1385 | 1403 | ||
1386 | add_root_to_dirty_list(root); | 1404 | add_root_to_dirty_list(root); |
@@ -1455,6 +1473,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
1455 | } else { | 1473 | } else { |
1456 | struct btrfs_disk_key right_key; | 1474 | struct btrfs_disk_key right_key; |
1457 | btrfs_node_key(right, &right_key, 0); | 1475 | btrfs_node_key(right, &right_key, 0); |
1476 | tree_mod_log_set_node_key(root->fs_info, parent, | ||
1477 | &right_key, pslot + 1, 0); | ||
1458 | btrfs_set_node_key(parent, &right_key, pslot + 1); | 1478 | btrfs_set_node_key(parent, &right_key, pslot + 1); |
1459 | btrfs_mark_buffer_dirty(parent); | 1479 | btrfs_mark_buffer_dirty(parent); |
1460 | } | 1480 | } |
@@ -1498,6 +1518,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
1498 | /* update the parent key to reflect our changes */ | 1518 | /* update the parent key to reflect our changes */ |
1499 | struct btrfs_disk_key mid_key; | 1519 | struct btrfs_disk_key mid_key; |
1500 | btrfs_node_key(mid, &mid_key, 0); | 1520 | btrfs_node_key(mid, &mid_key, 0); |
1521 | tree_mod_log_set_node_key(root->fs_info, parent, &mid_key, | ||
1522 | pslot, 0); | ||
1501 | btrfs_set_node_key(parent, &mid_key, pslot); | 1523 | btrfs_set_node_key(parent, &mid_key, pslot); |
1502 | btrfs_mark_buffer_dirty(parent); | 1524 | btrfs_mark_buffer_dirty(parent); |
1503 | } | 1525 | } |
@@ -1595,6 +1617,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, | |||
1595 | struct btrfs_disk_key disk_key; | 1617 | struct btrfs_disk_key disk_key; |
1596 | orig_slot += left_nr; | 1618 | orig_slot += left_nr; |
1597 | btrfs_node_key(mid, &disk_key, 0); | 1619 | btrfs_node_key(mid, &disk_key, 0); |
1620 | tree_mod_log_set_node_key(root->fs_info, parent, | ||
1621 | &disk_key, pslot, 0); | ||
1598 | btrfs_set_node_key(parent, &disk_key, pslot); | 1622 | btrfs_set_node_key(parent, &disk_key, pslot); |
1599 | btrfs_mark_buffer_dirty(parent); | 1623 | btrfs_mark_buffer_dirty(parent); |
1600 | if (btrfs_header_nritems(left) > orig_slot) { | 1624 | if (btrfs_header_nritems(left) > orig_slot) { |
@@ -1646,6 +1670,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, | |||
1646 | struct btrfs_disk_key disk_key; | 1670 | struct btrfs_disk_key disk_key; |
1647 | 1671 | ||
1648 | btrfs_node_key(right, &disk_key, 0); | 1672 | btrfs_node_key(right, &disk_key, 0); |
1673 | tree_mod_log_set_node_key(root->fs_info, parent, | ||
1674 | &disk_key, pslot + 1, 0); | ||
1649 | btrfs_set_node_key(parent, &disk_key, pslot + 1); | 1675 | btrfs_set_node_key(parent, &disk_key, pslot + 1); |
1650 | btrfs_mark_buffer_dirty(parent); | 1676 | btrfs_mark_buffer_dirty(parent); |
1651 | 1677 | ||
@@ -2348,6 +2374,7 @@ static void fixup_low_keys(struct btrfs_trans_handle *trans, | |||
2348 | if (!path->nodes[i]) | 2374 | if (!path->nodes[i]) |
2349 | break; | 2375 | break; |
2350 | t = path->nodes[i]; | 2376 | t = path->nodes[i]; |
2377 | tree_mod_log_set_node_key(root->fs_info, t, key, tslot, 1); | ||
2351 | btrfs_set_node_key(t, key, tslot); | 2378 | btrfs_set_node_key(t, key, tslot); |
2352 | btrfs_mark_buffer_dirty(path->nodes[i]); | 2379 | btrfs_mark_buffer_dirty(path->nodes[i]); |
2353 | if (tslot != 0) | 2380 | if (tslot != 0) |
@@ -2430,12 +2457,16 @@ static int push_node_left(struct btrfs_trans_handle *trans, | |||
2430 | } else | 2457 | } else |
2431 | push_items = min(src_nritems - 8, push_items); | 2458 | push_items = min(src_nritems - 8, push_items); |
2432 | 2459 | ||
2460 | tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0, | ||
2461 | push_items); | ||
2433 | copy_extent_buffer(dst, src, | 2462 | copy_extent_buffer(dst, src, |
2434 | btrfs_node_key_ptr_offset(dst_nritems), | 2463 | btrfs_node_key_ptr_offset(dst_nritems), |
2435 | btrfs_node_key_ptr_offset(0), | 2464 | btrfs_node_key_ptr_offset(0), |
2436 | push_items * sizeof(struct btrfs_key_ptr)); | 2465 | push_items * sizeof(struct btrfs_key_ptr)); |
2437 | 2466 | ||
2438 | if (push_items < src_nritems) { | 2467 | if (push_items < src_nritems) { |
2468 | tree_mod_log_eb_move(root->fs_info, src, 0, push_items, | ||
2469 | src_nritems - push_items); | ||
2439 | memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0), | 2470 | memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0), |
2440 | btrfs_node_key_ptr_offset(push_items), | 2471 | btrfs_node_key_ptr_offset(push_items), |
2441 | (src_nritems - push_items) * | 2472 | (src_nritems - push_items) * |
@@ -2489,11 +2520,14 @@ static int balance_node_right(struct btrfs_trans_handle *trans, | |||
2489 | if (max_push < push_items) | 2520 | if (max_push < push_items) |
2490 | push_items = max_push; | 2521 | push_items = max_push; |
2491 | 2522 | ||
2523 | tree_mod_log_eb_move(root->fs_info, dst, push_items, 0, dst_nritems); | ||
2492 | memmove_extent_buffer(dst, btrfs_node_key_ptr_offset(push_items), | 2524 | memmove_extent_buffer(dst, btrfs_node_key_ptr_offset(push_items), |
2493 | btrfs_node_key_ptr_offset(0), | 2525 | btrfs_node_key_ptr_offset(0), |
2494 | (dst_nritems) * | 2526 | (dst_nritems) * |
2495 | sizeof(struct btrfs_key_ptr)); | 2527 | sizeof(struct btrfs_key_ptr)); |
2496 | 2528 | ||
2529 | tree_mod_log_eb_copy(root->fs_info, dst, src, 0, | ||
2530 | src_nritems - push_items, push_items); | ||
2497 | copy_extent_buffer(dst, src, | 2531 | copy_extent_buffer(dst, src, |
2498 | btrfs_node_key_ptr_offset(0), | 2532 | btrfs_node_key_ptr_offset(0), |
2499 | btrfs_node_key_ptr_offset(src_nritems - push_items), | 2533 | btrfs_node_key_ptr_offset(src_nritems - push_items), |
@@ -2568,6 +2602,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans, | |||
2568 | btrfs_mark_buffer_dirty(c); | 2602 | btrfs_mark_buffer_dirty(c); |
2569 | 2603 | ||
2570 | old = root->node; | 2604 | old = root->node; |
2605 | tree_mod_log_set_root_pointer(root, c); | ||
2571 | rcu_assign_pointer(root->node, c); | 2606 | rcu_assign_pointer(root->node, c); |
2572 | 2607 | ||
2573 | /* the super has an extra ref to root->node */ | 2608 | /* the super has an extra ref to root->node */ |
@@ -2678,6 +2713,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans, | |||
2678 | (unsigned long)btrfs_header_chunk_tree_uuid(split), | 2713 | (unsigned long)btrfs_header_chunk_tree_uuid(split), |
2679 | BTRFS_UUID_SIZE); | 2714 | BTRFS_UUID_SIZE); |
2680 | 2715 | ||
2716 | tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid); | ||
2681 | copy_extent_buffer(split, c, | 2717 | copy_extent_buffer(split, c, |
2682 | btrfs_node_key_ptr_offset(0), | 2718 | btrfs_node_key_ptr_offset(0), |
2683 | btrfs_node_key_ptr_offset(mid), | 2719 | btrfs_node_key_ptr_offset(mid), |