Commit f230475e authored by Jan Schmidt's avatar Jan Schmidt

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: default avatarJan Schmidt <list.btrfs@jan-o-sch.net>
parent bd989ba3
...@@ -39,6 +39,14 @@ static int balance_node_right(struct btrfs_trans_handle *trans, ...@@ -39,6 +39,14 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
struct extent_buffer *src_buf); struct extent_buffer *src_buf);
static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_path *path, int level, int slot); struct btrfs_path *path, int level, int slot);
static void tree_mod_log_free_eb(struct btrfs_fs_info *fs_info,
struct extent_buffer *eb);
struct extent_buffer *read_old_tree_block(struct btrfs_root *root, u64 bytenr,
u32 blocksize, u64 parent_transid,
u64 time_seq);
struct extent_buffer *btrfs_find_old_tree_block(struct btrfs_root *root,
u64 bytenr, u32 blocksize,
u64 time_seq);
struct btrfs_path *btrfs_alloc_path(void) struct btrfs_path *btrfs_alloc_path(void)
{ {
...@@ -816,6 +824,12 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, ...@@ -816,6 +824,12 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
ret = btrfs_dec_ref(trans, root, buf, 1, 1); ret = btrfs_dec_ref(trans, root, buf, 1, 1);
BUG_ON(ret); /* -ENOMEM */ BUG_ON(ret); /* -ENOMEM */
} }
/*
* don't log freeing in case we're freeing the root node, this
* is done by tree_mod_log_set_root_pointer later
*/
if (buf != root->node && btrfs_header_level(buf) != 0)
tree_mod_log_free_eb(root->fs_info, buf);
clean_tree_block(trans, root, buf); clean_tree_block(trans, root, buf);
*last_ref = 1; *last_ref = 1;
} }
...@@ -913,6 +927,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, ...@@ -913,6 +927,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
parent_start = 0; parent_start = 0;
extent_buffer_get(cow); extent_buffer_get(cow);
tree_mod_log_set_root_pointer(root, cow);
rcu_assign_pointer(root->node, cow); rcu_assign_pointer(root->node, cow);
btrfs_free_tree_block(trans, root, buf, parent_start, 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,6 +941,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
parent_start = 0; parent_start = 0;
WARN_ON(trans->transid != btrfs_header_generation(parent)); WARN_ON(trans->transid != btrfs_header_generation(parent));
tree_mod_log_insert_key(root->fs_info, parent, parent_slot,
MOD_LOG_KEY_REPLACE);
btrfs_set_node_blockptr(parent, parent_slot, btrfs_set_node_blockptr(parent, parent_slot,
cow->start); cow->start);
btrfs_set_node_ptr_generation(parent, parent_slot, btrfs_set_node_ptr_generation(parent, parent_slot,
...@@ -1381,6 +1398,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -1381,6 +1398,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
goto enospc; goto enospc;
} }
tree_mod_log_set_root_pointer(root, child);
rcu_assign_pointer(root->node, child); rcu_assign_pointer(root->node, child);
add_root_to_dirty_list(root); add_root_to_dirty_list(root);
...@@ -1455,6 +1473,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -1455,6 +1473,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
} else { } else {
struct btrfs_disk_key right_key; struct btrfs_disk_key right_key;
btrfs_node_key(right, &right_key, 0); btrfs_node_key(right, &right_key, 0);
tree_mod_log_set_node_key(root->fs_info, parent,
&right_key, pslot + 1, 0);
btrfs_set_node_key(parent, &right_key, pslot + 1); btrfs_set_node_key(parent, &right_key, pslot + 1);
btrfs_mark_buffer_dirty(parent); btrfs_mark_buffer_dirty(parent);
} }
...@@ -1498,6 +1518,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -1498,6 +1518,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
/* update the parent key to reflect our changes */ /* update the parent key to reflect our changes */
struct btrfs_disk_key mid_key; struct btrfs_disk_key mid_key;
btrfs_node_key(mid, &mid_key, 0); btrfs_node_key(mid, &mid_key, 0);
tree_mod_log_set_node_key(root->fs_info, parent, &mid_key,
pslot, 0);
btrfs_set_node_key(parent, &mid_key, pslot); btrfs_set_node_key(parent, &mid_key, pslot);
btrfs_mark_buffer_dirty(parent); btrfs_mark_buffer_dirty(parent);
} }
...@@ -1595,6 +1617,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, ...@@ -1595,6 +1617,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
struct btrfs_disk_key disk_key; struct btrfs_disk_key disk_key;
orig_slot += left_nr; orig_slot += left_nr;
btrfs_node_key(mid, &disk_key, 0); btrfs_node_key(mid, &disk_key, 0);
tree_mod_log_set_node_key(root->fs_info, parent,
&disk_key, pslot, 0);
btrfs_set_node_key(parent, &disk_key, pslot); btrfs_set_node_key(parent, &disk_key, pslot);
btrfs_mark_buffer_dirty(parent); btrfs_mark_buffer_dirty(parent);
if (btrfs_header_nritems(left) > orig_slot) { if (btrfs_header_nritems(left) > orig_slot) {
...@@ -1646,6 +1670,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, ...@@ -1646,6 +1670,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
struct btrfs_disk_key disk_key; struct btrfs_disk_key disk_key;
btrfs_node_key(right, &disk_key, 0); btrfs_node_key(right, &disk_key, 0);
tree_mod_log_set_node_key(root->fs_info, parent,
&disk_key, pslot + 1, 0);
btrfs_set_node_key(parent, &disk_key, pslot + 1); btrfs_set_node_key(parent, &disk_key, pslot + 1);
btrfs_mark_buffer_dirty(parent); btrfs_mark_buffer_dirty(parent);
...@@ -2348,6 +2374,7 @@ static void fixup_low_keys(struct btrfs_trans_handle *trans, ...@@ -2348,6 +2374,7 @@ static void fixup_low_keys(struct btrfs_trans_handle *trans,
if (!path->nodes[i]) if (!path->nodes[i])
break; break;
t = path->nodes[i]; t = path->nodes[i];
tree_mod_log_set_node_key(root->fs_info, t, key, tslot, 1);
btrfs_set_node_key(t, key, tslot); btrfs_set_node_key(t, key, tslot);
btrfs_mark_buffer_dirty(path->nodes[i]); btrfs_mark_buffer_dirty(path->nodes[i]);
if (tslot != 0) if (tslot != 0)
...@@ -2430,12 +2457,16 @@ static int push_node_left(struct btrfs_trans_handle *trans, ...@@ -2430,12 +2457,16 @@ static int push_node_left(struct btrfs_trans_handle *trans,
} else } else
push_items = min(src_nritems - 8, push_items); push_items = min(src_nritems - 8, push_items);
tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0,
push_items);
copy_extent_buffer(dst, src, copy_extent_buffer(dst, src,
btrfs_node_key_ptr_offset(dst_nritems), btrfs_node_key_ptr_offset(dst_nritems),
btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(0),
push_items * sizeof(struct btrfs_key_ptr)); push_items * sizeof(struct btrfs_key_ptr));
if (push_items < src_nritems) { if (push_items < src_nritems) {
tree_mod_log_eb_move(root->fs_info, src, 0, push_items,
src_nritems - push_items);
memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0), memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0),
btrfs_node_key_ptr_offset(push_items), btrfs_node_key_ptr_offset(push_items),
(src_nritems - push_items) * (src_nritems - push_items) *
...@@ -2489,11 +2520,14 @@ static int balance_node_right(struct btrfs_trans_handle *trans, ...@@ -2489,11 +2520,14 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
if (max_push < push_items) if (max_push < push_items)
push_items = max_push; push_items = max_push;
tree_mod_log_eb_move(root->fs_info, dst, push_items, 0, dst_nritems);
memmove_extent_buffer(dst, btrfs_node_key_ptr_offset(push_items), memmove_extent_buffer(dst, btrfs_node_key_ptr_offset(push_items),
btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(0),
(dst_nritems) * (dst_nritems) *
sizeof(struct btrfs_key_ptr)); sizeof(struct btrfs_key_ptr));
tree_mod_log_eb_copy(root->fs_info, dst, src, 0,
src_nritems - push_items, push_items);
copy_extent_buffer(dst, src, copy_extent_buffer(dst, src,
btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(0),
btrfs_node_key_ptr_offset(src_nritems - push_items), 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,6 +2602,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(c); btrfs_mark_buffer_dirty(c);
old = root->node; old = root->node;
tree_mod_log_set_root_pointer(root, c);
rcu_assign_pointer(root->node, c); rcu_assign_pointer(root->node, c);
/* the super has an extra ref to root->node */ /* the super has an extra ref to root->node */
...@@ -2678,6 +2713,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans, ...@@ -2678,6 +2713,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
(unsigned long)btrfs_header_chunk_tree_uuid(split), (unsigned long)btrfs_header_chunk_tree_uuid(split),
BTRFS_UUID_SIZE); BTRFS_UUID_SIZE);
tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid);
copy_extent_buffer(split, c, copy_extent_buffer(split, c,
btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(0),
btrfs_node_key_ptr_offset(mid), btrfs_node_key_ptr_offset(mid),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment