Commit c657c3ef authored by Chris Mason's avatar Chris Mason

Merge branch 'for-chris-fixed' of git://git.jan-o-sch.net/btrfs-unstable

parents be6aef60 01763a2e
...@@ -283,9 +283,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, ...@@ -283,9 +283,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
goto out; goto out;
} }
rcu_read_lock(); root_level = btrfs_old_root_level(root, time_seq);
root_level = btrfs_header_level(root->node);
rcu_read_unlock();
if (root_level + 1 == level) if (root_level + 1 == level)
goto out; goto out;
......
...@@ -596,6 +596,11 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info, ...@@ -596,6 +596,11 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
if (tree_mod_dont_log(fs_info, eb)) if (tree_mod_dont_log(fs_info, eb))
return 0; return 0;
/*
* When we override something during the move, we log these removals.
* This can only happen when we move towards the beginning of the
* buffer, i.e. dst_slot < src_slot.
*/
for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) {
ret = tree_mod_log_insert_key_locked(fs_info, eb, i + dst_slot, ret = tree_mod_log_insert_key_locked(fs_info, eb, i + dst_slot,
MOD_LOG_KEY_REMOVE_WHILE_MOVING); MOD_LOG_KEY_REMOVE_WHILE_MOVING);
...@@ -647,8 +652,6 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info, ...@@ -647,8 +652,6 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
if (tree_mod_dont_log(fs_info, NULL)) if (tree_mod_dont_log(fs_info, NULL))
return 0; return 0;
__tree_mod_log_free_eb(fs_info, old_root);
ret = tree_mod_alloc(fs_info, flags, &tm); ret = tree_mod_alloc(fs_info, flags, &tm);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -926,12 +929,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, ...@@ -926,12 +929,7 @@ 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 */
} }
/* tree_mod_log_free_eb(root->fs_info, buf);
* 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;
} }
...@@ -1225,6 +1223,8 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, ...@@ -1225,6 +1223,8 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
free_extent_buffer(eb); free_extent_buffer(eb);
__tree_mod_log_rewind(eb_rewin, time_seq, tm); __tree_mod_log_rewind(eb_rewin, time_seq, tm);
WARN_ON(btrfs_header_nritems(eb_rewin) >
BTRFS_NODEPTRS_PER_BLOCK(fs_info->fs_root));
return eb_rewin; return eb_rewin;
} }
...@@ -1244,6 +1244,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq) ...@@ -1244,6 +1244,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
struct tree_mod_root *old_root = NULL; struct tree_mod_root *old_root = NULL;
u64 old_generation = 0; u64 old_generation = 0;
u64 logical; u64 logical;
u32 blocksize;
eb = btrfs_read_lock_root_node(root); eb = btrfs_read_lock_root_node(root);
tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq); 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,14 +1260,31 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
} }
tm = tree_mod_log_search(root->fs_info, logical, time_seq); tm = tree_mod_log_search(root->fs_info, logical, time_seq);
if (old_root) if (old_root && tm && tm->op != MOD_LOG_KEY_REMOVE_WHILE_FREEING) {
btrfs_tree_read_unlock(root->node);
free_extent_buffer(root->node);
blocksize = btrfs_level_size(root, old_root->level);
eb = read_tree_block(root, logical, blocksize, 0);
if (!eb) {
pr_warn("btrfs: failed to read tree block %llu from get_old_root\n",
logical);
WARN_ON(1);
} else {
eb = btrfs_clone_extent_buffer(eb);
}
} else if (old_root) {
btrfs_tree_read_unlock(root->node);
free_extent_buffer(root->node);
eb = alloc_dummy_extent_buffer(logical, root->nodesize); eb = alloc_dummy_extent_buffer(logical, root->nodesize);
else } else {
eb = btrfs_clone_extent_buffer(root->node); eb = btrfs_clone_extent_buffer(root->node);
btrfs_tree_read_unlock(root->node); btrfs_tree_read_unlock(root->node);
free_extent_buffer(root->node); free_extent_buffer(root->node);
}
if (!eb) if (!eb)
return NULL; return NULL;
extent_buffer_get(eb);
btrfs_tree_read_lock(eb); btrfs_tree_read_lock(eb);
if (old_root) { if (old_root) {
btrfs_set_header_bytenr(eb, eb->start); btrfs_set_header_bytenr(eb, eb->start);
...@@ -1279,11 +1297,28 @@ get_old_root(struct btrfs_root *root, u64 time_seq) ...@@ -1279,11 +1297,28 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
__tree_mod_log_rewind(eb, time_seq, tm); __tree_mod_log_rewind(eb, time_seq, tm);
else else
WARN_ON(btrfs_header_level(eb) != 0); WARN_ON(btrfs_header_level(eb) != 0);
extent_buffer_get(eb); WARN_ON(btrfs_header_nritems(eb) > BTRFS_NODEPTRS_PER_BLOCK(root));
return eb; return eb;
} }
int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq)
{
struct tree_mod_elem *tm;
int level;
tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq);
if (tm && tm->op == MOD_LOG_ROOT_REPLACE) {
level = tm->old_root.level;
} else {
rcu_read_lock();
level = btrfs_header_level(root->node);
rcu_read_unlock();
}
return level;
}
static inline int should_cow_block(struct btrfs_trans_handle *trans, static inline int should_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct extent_buffer *buf) struct extent_buffer *buf)
...@@ -1725,6 +1760,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -1725,6 +1760,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
goto enospc; goto enospc;
} }
tree_mod_log_free_eb(root->fs_info, root->node);
tree_mod_log_set_root_pointer(root, child); tree_mod_log_set_root_pointer(root, child);
rcu_assign_pointer(root->node, child); rcu_assign_pointer(root->node, child);
...@@ -2970,8 +3006,10 @@ static int push_node_left(struct btrfs_trans_handle *trans, ...@@ -2970,8 +3006,10 @@ static int push_node_left(struct btrfs_trans_handle *trans,
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); * don't call tree_mod_log_eb_move here, key removal was already
* fully logged by tree_mod_log_eb_copy above.
*/
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) *
......
...@@ -3120,6 +3120,7 @@ static inline u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info) ...@@ -3120,6 +3120,7 @@ static inline u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info)
{ {
return atomic_inc_return(&fs_info->tree_mod_seq); return atomic_inc_return(&fs_info->tree_mod_seq);
} }
int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq);
/* root-item.c */ /* root-item.c */
int btrfs_find_root_ref(struct btrfs_root *tree_root, int btrfs_find_root_ref(struct btrfs_root *tree_root,
......
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