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

Commit f421950f authored by Chris Mason's avatar Chris Mason
Browse files

Btrfs: Fix some data=ordered related data corruptions



Stress testing was showing data checksum errors, most of which were caused
by a lookup bug in the extent_map tree.  The tree was caching the last
pointer returned, and searches would check the last pointer first.

But, search callers also expect the search to return the very first
matching extent in the range, which wasn't always true with the last
pointer usage.

For now, the code to cache the last return value is just removed.  It is
easy to fix, but I think lookups are rare enough that it isn't required anymore.

This commit also replaces do_sync_mapping_range with a local copy of the
related functions.

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent a61e6f29
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1590,6 +1590,8 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
			struct btrfs_root *root, struct btrfs_path *path,
			u64 isize);
/* inode.c */
int btrfs_writepages(struct address_space *mapping,
		     struct writeback_control *wbc);
int btrfs_create_subvol_root(struct btrfs_root *new_root,
		struct btrfs_trans_handle *trans, u64 new_dirid,
		struct btrfs_block_group_cache *block_group);
+0 −20
Original line number Diff line number Diff line
@@ -97,7 +97,6 @@ void extent_io_tree_init(struct extent_io_tree *tree,
	spin_lock_init(&tree->lock);
	spin_lock_init(&tree->buffer_lock);
	tree->mapping = mapping;
	tree->last = NULL;
}
EXPORT_SYMBOL(extent_io_tree_init);

@@ -173,12 +172,6 @@ static struct rb_node *__etree_search(struct extent_io_tree *tree, u64 offset,
	struct tree_entry *entry;
	struct tree_entry *prev_entry = NULL;

	if (tree->last) {
		struct extent_state *state;
		state = tree->last;
		if (state->start <= offset && offset <= state->end)
			return &tree->last->rb_node;
	}
	while(n) {
		entry = rb_entry(n, struct tree_entry, rb_node);
		prev = n;
@@ -189,7 +182,6 @@ static struct rb_node *__etree_search(struct extent_io_tree *tree, u64 offset,
		else if (offset > entry->end)
			n = n->rb_right;
		else {
			tree->last = rb_entry(n, struct extent_state, rb_node);
			return n;
		}
	}
@@ -223,10 +215,6 @@ static inline struct rb_node *tree_search(struct extent_io_tree *tree,

	ret = __etree_search(tree, offset, &prev, NULL);
	if (!ret) {
		if (prev) {
			tree->last = rb_entry(prev, struct extent_state,
					      rb_node);
		}
		return prev;
	}
	return ret;
@@ -301,8 +289,6 @@ static int merge_state(struct extent_io_tree *tree,
		    other->state == state->state) {
			state->start = other->start;
			other->tree = NULL;
			if (tree->last == other)
				tree->last = state;
			rb_erase(&other->rb_node, &tree->state);
			free_extent_state(other);
		}
@@ -314,8 +300,6 @@ static int merge_state(struct extent_io_tree *tree,
		    other->state == state->state) {
			other->start = state->start;
			state->tree = NULL;
			if (tree->last == state)
				tree->last = other;
			rb_erase(&state->rb_node, &tree->state);
			free_extent_state(state);
		}
@@ -378,7 +362,6 @@ static int insert_state(struct extent_io_tree *tree,
		return -EEXIST;
	}
	state->tree = tree;
	tree->last = state;
	merge_state(tree, state);
	return 0;
}
@@ -444,9 +427,6 @@ static int clear_state_bit(struct extent_io_tree *tree,
	if (delete || state->state == 0) {
		if (state->tree) {
			clear_state_cb(tree, state, state->state);
			if (tree->last == state) {
				tree->last = extent_state_next(state);
			}
			rb_erase(&state->rb_node, &tree->state);
			state->tree = NULL;
			free_extent_state(state);
+0 −1
Original line number Diff line number Diff line
@@ -60,7 +60,6 @@ struct extent_io_tree {
	spinlock_t lock;
	spinlock_t buffer_lock;
	struct extent_io_ops *ops;
	struct extent_state *last;
};

struct extent_state {
+0 −9
Original line number Diff line number Diff line
@@ -42,7 +42,6 @@ void extent_map_exit(void)
void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask)
{
	tree->map.rb_node = NULL;
	tree->last = NULL;
	spin_lock_init(&tree->lock);
}
EXPORT_SYMBOL(extent_map_tree_init);
@@ -239,7 +238,6 @@ int add_extent_mapping(struct extent_map_tree *tree,
		merge->in_tree = 0;
		free_extent_map(merge);
	}
	tree->last = em;
out:
	return ret;
}
@@ -273,10 +271,6 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
	u64 end = range_end(start, len);

	BUG_ON(spin_trylock(&tree->lock));
	em = tree->last;
	if (em && end > em->start && start < extent_map_end(em))
		goto found;

	rb_node = __tree_search(&tree->map, start, &prev, &next);
	if (!rb_node && prev) {
		em = rb_entry(prev, struct extent_map, rb_node);
@@ -305,7 +299,6 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,

found:
	atomic_inc(&em->refs);
	tree->last = em;
out:
	return em;
}
@@ -327,8 +320,6 @@ int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em)
	BUG_ON(spin_trylock(&tree->lock));
	rb_erase(&em->rb_node, &tree->map);
	em->in_tree = 0;
	if (tree->last == em)
		tree->last = NULL;
	return ret;
}
EXPORT_SYMBOL(remove_extent_mapping);
+0 −1
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ struct extent_map {

struct extent_map_tree {
	struct rb_root map;
	struct extent_map *last;
	spinlock_t lock;
};

Loading