Commit 50b5d1fc authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba
Browse files

btrfs: do not BUG_ON() on tree mod log failures at insert_ptr()



At insert_ptr(), instead of doing a BUG_ON() in case we fail to record
tree mod log operations, do a transaction abort and return the error to
the callers. There's really no need for the BUG_ON() as we can release all
resources in the context of all callers, and we have to abort because other
future tree searches that use the tree mod log (btrfs_search_old_slot())
may get inconsistent results if other operations modify the tree after
that failure and before the tree mod log based search.

This implies making insert_ptr() return an int instead of void, and making
all callers check for returned errors.

Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent f61aa7ba
Loading
Loading
Loading
Loading
+52 −19
Original line number Diff line number Diff line
@@ -2990,7 +2990,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
 * slot and level indicate where you want the key to go, and
 * blocknr is the block the key points to.
 */
static void insert_ptr(struct btrfs_trans_handle *trans,
static int insert_ptr(struct btrfs_trans_handle *trans,
		      struct btrfs_path *path,
		      struct btrfs_disk_key *key, u64 bytenr,
		      int slot, int level)
@@ -3009,7 +3009,10 @@ static void insert_ptr(struct btrfs_trans_handle *trans,
		if (level) {
			ret = btrfs_tree_mod_log_insert_move(lower, slot + 1,
					slot, nritems - slot);
			BUG_ON(ret < 0);
			if (ret < 0) {
				btrfs_abort_transaction(trans, ret);
				return ret;
			}
		}
		memmove_extent_buffer(lower,
			      btrfs_node_key_ptr_offset(lower, slot + 1),
@@ -3019,7 +3022,10 @@ static void insert_ptr(struct btrfs_trans_handle *trans,
	if (level) {
		ret = btrfs_tree_mod_log_insert_key(lower, slot,
						    BTRFS_MOD_LOG_KEY_ADD);
		BUG_ON(ret < 0);
		if (ret < 0) {
			btrfs_abort_transaction(trans, ret);
			return ret;
		}
	}
	btrfs_set_node_key(lower, key, slot);
	btrfs_set_node_blockptr(lower, slot, bytenr);
@@ -3027,6 +3033,8 @@ static void insert_ptr(struct btrfs_trans_handle *trans,
	btrfs_set_node_ptr_generation(lower, slot, trans->transid);
	btrfs_set_header_nritems(lower, nritems + 1);
	btrfs_mark_buffer_dirty(lower);

	return 0;
}

/*
@@ -3106,8 +3114,13 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
	btrfs_mark_buffer_dirty(c);
	btrfs_mark_buffer_dirty(split);

	insert_ptr(trans, path, &disk_key, split->start,
	ret = insert_ptr(trans, path, &disk_key, split->start,
			 path->slots[level + 1] + 1, level + 1);
	if (ret < 0) {
		btrfs_tree_unlock(split);
		free_extent_buffer(split);
		return ret;
	}

	if (path->slots[level] >= mid) {
		path->slots[level] -= mid;
@@ -3584,7 +3597,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
 * split the path's leaf in two, making sure there is at least data_size
 * available for the resulting leaf level of the path.
 */
static noinline void copy_for_split(struct btrfs_trans_handle *trans,
static noinline int copy_for_split(struct btrfs_trans_handle *trans,
				   struct btrfs_path *path,
				   struct extent_buffer *l,
				   struct extent_buffer *right,
@@ -3594,6 +3607,7 @@ static noinline void copy_for_split(struct btrfs_trans_handle *trans,
	int data_copy_size;
	int rt_data_off;
	int i;
	int ret;
	struct btrfs_disk_key disk_key;
	struct btrfs_map_token token;

@@ -3618,7 +3632,9 @@ static noinline void copy_for_split(struct btrfs_trans_handle *trans,

	btrfs_set_header_nritems(l, mid);
	btrfs_item_key(right, &disk_key, 0);
	insert_ptr(trans, path, &disk_key, right->start, path->slots[1] + 1, 1);
	ret = insert_ptr(trans, path, &disk_key, right->start, path->slots[1] + 1, 1);
	if (ret < 0)
		return ret;

	btrfs_mark_buffer_dirty(right);
	btrfs_mark_buffer_dirty(l);
@@ -3636,6 +3652,8 @@ static noinline void copy_for_split(struct btrfs_trans_handle *trans,
	}

	BUG_ON(path->slots[0] < 0);

	return 0;
}

/*
@@ -3834,8 +3852,13 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
	if (split == 0) {
		if (mid <= slot) {
			btrfs_set_header_nritems(right, 0);
			insert_ptr(trans, path, &disk_key,
			ret = insert_ptr(trans, path, &disk_key,
					 right->start, path->slots[1] + 1, 1);
			if (ret < 0) {
				btrfs_tree_unlock(right);
				free_extent_buffer(right);
				return ret;
			}
			btrfs_tree_unlock(path->nodes[0]);
			free_extent_buffer(path->nodes[0]);
			path->nodes[0] = right;
@@ -3843,8 +3866,13 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
			path->slots[1] += 1;
		} else {
			btrfs_set_header_nritems(right, 0);
			insert_ptr(trans, path, &disk_key,
			ret = insert_ptr(trans, path, &disk_key,
					 right->start, path->slots[1], 1);
			if (ret < 0) {
				btrfs_tree_unlock(right);
				free_extent_buffer(right);
				return ret;
			}
			btrfs_tree_unlock(path->nodes[0]);
			free_extent_buffer(path->nodes[0]);
			path->nodes[0] = right;
@@ -3860,7 +3888,12 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
		return ret;
	}

	copy_for_split(trans, path, l, right, slot, mid, nritems);
	ret = copy_for_split(trans, path, l, right, slot, mid, nritems);
	if (ret < 0) {
		btrfs_tree_unlock(right);
		free_extent_buffer(right);
		return ret;
	}

	if (split == 2) {
		BUG_ON(num_doubles != 0);