Skip to content

Commit

Permalink
Merge tag 'for-6.6-rc7-tag' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/kdave/linux

Pull btrfs fix from David Sterba:
 "One more fix for a problem with snapshot of a newly created subvolume
  that can lead to inconsistent data under some circumstances. Kernel
  6.5 added a performance optimization to skip transaction commit for
  subvolume creation but this could end up with newer data on disk but
  not linked to other structures.

  The fix itself is an added condition, the rest of the patch is a
  parameter added to several functions"

* tag 'for-6.6-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: fix unwritten extent buffer after snapshotting a new subvolume
  • Loading branch information
Linus Torvalds committed Oct 23, 2023
2 parents 7c14564 + eb96e22 commit e017769
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 15 deletions.
14 changes: 9 additions & 5 deletions fs/btrfs/backref.c
Original file line number Diff line number Diff line change
Expand Up @@ -3196,12 +3196,14 @@ static int handle_direct_tree_backref(struct btrfs_backref_cache *cache,
* We still need to do a tree search to find out the parents. This is for
* TREE_BLOCK_REF backref (keyed or inlined).
*
* @trans: Transaction handle.
* @ref_key: The same as @ref_key in handle_direct_tree_backref()
* @tree_key: The first key of this tree block.
* @path: A clean (released) path, to avoid allocating path every time
* the function get called.
*/
static int handle_indirect_tree_backref(struct btrfs_backref_cache *cache,
static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans,
struct btrfs_backref_cache *cache,
struct btrfs_path *path,
struct btrfs_key *ref_key,
struct btrfs_key *tree_key,
Expand Down Expand Up @@ -3315,7 +3317,7 @@ static int handle_indirect_tree_backref(struct btrfs_backref_cache *cache,
* If we know the block isn't shared we can avoid
* checking its backrefs.
*/
if (btrfs_block_can_be_shared(root, eb))
if (btrfs_block_can_be_shared(trans, root, eb))
upper->checked = 0;
else
upper->checked = 1;
Expand Down Expand Up @@ -3363,11 +3365,13 @@ static int handle_indirect_tree_backref(struct btrfs_backref_cache *cache,
* links aren't yet bi-directional. Needs to finish such links.
* Use btrfs_backref_finish_upper_links() to finish such linkage.
*
* @trans: Transaction handle.
* @path: Released path for indirect tree backref lookup
* @iter: Released backref iter for extent tree search
* @node_key: The first key of the tree block
*/
int btrfs_backref_add_tree_node(struct btrfs_backref_cache *cache,
int btrfs_backref_add_tree_node(struct btrfs_trans_handle *trans,
struct btrfs_backref_cache *cache,
struct btrfs_path *path,
struct btrfs_backref_iter *iter,
struct btrfs_key *node_key,
Expand Down Expand Up @@ -3467,8 +3471,8 @@ int btrfs_backref_add_tree_node(struct btrfs_backref_cache *cache,
* offset means the root objectid. We need to search
* the tree to get its parent bytenr.
*/
ret = handle_indirect_tree_backref(cache, path, &key, node_key,
cur);
ret = handle_indirect_tree_backref(trans, cache, path,
&key, node_key, cur);
if (ret < 0)
goto out;
}
Expand Down
3 changes: 2 additions & 1 deletion fs/btrfs/backref.h
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,8 @@ static inline void btrfs_backref_panic(struct btrfs_fs_info *fs_info,
bytenr);
}

int btrfs_backref_add_tree_node(struct btrfs_backref_cache *cache,
int btrfs_backref_add_tree_node(struct btrfs_trans_handle *trans,
struct btrfs_backref_cache *cache,
struct btrfs_path *path,
struct btrfs_backref_iter *iter,
struct btrfs_key *node_key,
Expand Down
21 changes: 16 additions & 5 deletions fs/btrfs/ctree.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,8 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
/*
* check if the tree block can be shared by multiple trees
*/
int btrfs_block_can_be_shared(struct btrfs_root *root,
int btrfs_block_can_be_shared(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf)
{
/*
Expand All @@ -376,11 +377,21 @@ int btrfs_block_can_be_shared(struct btrfs_root *root,
* not allocated by tree relocation, we know the block is not shared.
*/
if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) &&
buf != root->node && buf != root->commit_root &&
buf != root->node &&
(btrfs_header_generation(buf) <=
btrfs_root_last_snapshot(&root->root_item) ||
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)))
return 1;
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) {
if (buf != root->commit_root)
return 1;
/*
* An extent buffer that used to be the commit root may still be
* shared because the tree height may have increased and it
* became a child of a higher level root. This can happen when
* snapshotting a subvolume created in the current transaction.
*/
if (btrfs_header_generation(buf) == trans->transid)
return 1;
}

return 0;
}
Expand Down Expand Up @@ -415,7 +426,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
* are only allowed for blocks use full backrefs.
*/

if (btrfs_block_can_be_shared(root, buf)) {
if (btrfs_block_can_be_shared(trans, root, buf)) {
ret = btrfs_lookup_extent_info(trans, fs_info, buf->start,
btrfs_header_level(buf), 1,
&refs, &flags);
Expand Down
3 changes: 2 additions & 1 deletion fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,8 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf,
struct extent_buffer **cow_ret, u64 new_root_objectid);
int btrfs_block_can_be_shared(struct btrfs_root *root,
int btrfs_block_can_be_shared(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf);
int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_path *path, int level, int slot);
Expand Down
7 changes: 4 additions & 3 deletions fs/btrfs/relocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ static bool handle_useless_nodes(struct reloc_control *rc,
* cached.
*/
static noinline_for_stack struct btrfs_backref_node *build_backref_tree(
struct btrfs_trans_handle *trans,
struct reloc_control *rc, struct btrfs_key *node_key,
int level, u64 bytenr)
{
Expand Down Expand Up @@ -499,8 +500,8 @@ static noinline_for_stack struct btrfs_backref_node *build_backref_tree(

/* Breadth-first search to build backref cache */
do {
ret = btrfs_backref_add_tree_node(cache, path, iter, node_key,
cur);
ret = btrfs_backref_add_tree_node(trans, cache, path, iter,
node_key, cur);
if (ret < 0) {
err = ret;
goto out;
Expand Down Expand Up @@ -2803,7 +2804,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans,

/* Do tree relocation */
rbtree_postorder_for_each_entry_safe(block, next, blocks, rb_node) {
node = build_backref_tree(rc, &block->key,
node = build_backref_tree(trans, rc, &block->key,
block->level, block->bytenr);
if (IS_ERR(node)) {
err = PTR_ERR(node);
Expand Down

0 comments on commit e017769

Please sign in to comment.