Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f230475e authored by Jan Schmidt's avatar Jan Schmidt
Browse files

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
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -39,6 +39,14 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
			      struct extent_buffer *src_buf);
static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		   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)
{
@@ -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);
			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);
		*last_ref = 1;
	}
@@ -913,6 +927,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
			parent_start = 0;

		extent_buffer_get(cow);
		tree_mod_log_set_root_pointer(root, cow);
		rcu_assign_pointer(root->node, cow);

		btrfs_free_tree_block(trans, root, buf, parent_start,
@@ -926,6 +941,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
			parent_start = 0;

		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,
					cow->start);
		btrfs_set_node_ptr_generation(parent, parent_slot,
@@ -1381,6 +1398,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
			goto enospc;
		}

		tree_mod_log_set_root_pointer(root, child);
		rcu_assign_pointer(root->node, child);

		add_root_to_dirty_list(root);
@@ -1455,6 +1473,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
		} else {
			struct btrfs_disk_key right_key;
			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_mark_buffer_dirty(parent);
		}
@@ -1498,6 +1518,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
		/* update the parent key to reflect our changes */
		struct btrfs_disk_key mid_key;
		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_mark_buffer_dirty(parent);
	}
@@ -1595,6 +1617,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
			struct btrfs_disk_key disk_key;
			orig_slot += left_nr;
			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_mark_buffer_dirty(parent);
			if (btrfs_header_nritems(left) > orig_slot) {
@@ -1646,6 +1670,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
			struct btrfs_disk_key disk_key;

			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_mark_buffer_dirty(parent);

@@ -2348,6 +2374,7 @@ static void fixup_low_keys(struct btrfs_trans_handle *trans,
		if (!path->nodes[i])
			break;
		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_mark_buffer_dirty(path->nodes[i]);
		if (tslot != 0)
@@ -2430,12 +2457,16 @@ static int push_node_left(struct btrfs_trans_handle *trans,
	} else
		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,
			   btrfs_node_key_ptr_offset(dst_nritems),
			   btrfs_node_key_ptr_offset(0),
			   push_items * sizeof(struct btrfs_key_ptr));

	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),
				      btrfs_node_key_ptr_offset(push_items),
				      (src_nritems - push_items) *
@@ -2489,11 +2520,14 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
	if (max_push < push_items)
		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),
				      btrfs_node_key_ptr_offset(0),
				      (dst_nritems) *
				      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,
			   btrfs_node_key_ptr_offset(0),
			   btrfs_node_key_ptr_offset(src_nritems - push_items),
@@ -2568,6 +2602,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
	btrfs_mark_buffer_dirty(c);

	old = root->node;
	tree_mod_log_set_root_pointer(root, c);
	rcu_assign_pointer(root->node, c);

	/* the super has an extra ref to root->node */
@@ -2678,6 +2713,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
			    (unsigned long)btrfs_header_chunk_tree_uuid(split),
			    BTRFS_UUID_SIZE);

	tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid);
	copy_extent_buffer(split, c,
			   btrfs_node_key_ptr_offset(0),
			   btrfs_node_key_ptr_offset(mid),