Skip to content

Commit e017769

Browse files
committed
Merge tag 'for-6.6-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/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
2 parents 7c14564 + eb96e22 commit e017769

File tree

5 files changed

+33
-15
lines changed

5 files changed

+33
-15
lines changed

fs/btrfs/backref.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3196,12 +3196,14 @@ static int handle_direct_tree_backref(struct btrfs_backref_cache *cache,
31963196
* We still need to do a tree search to find out the parents. This is for
31973197
* TREE_BLOCK_REF backref (keyed or inlined).
31983198
*
3199+
* @trans: Transaction handle.
31993200
* @ref_key: The same as @ref_key in handle_direct_tree_backref()
32003201
* @tree_key: The first key of this tree block.
32013202
* @path: A clean (released) path, to avoid allocating path every time
32023203
* the function get called.
32033204
*/
3204-
static int handle_indirect_tree_backref(struct btrfs_backref_cache *cache,
3205+
static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans,
3206+
struct btrfs_backref_cache *cache,
32053207
struct btrfs_path *path,
32063208
struct btrfs_key *ref_key,
32073209
struct btrfs_key *tree_key,
@@ -3315,7 +3317,7 @@ static int handle_indirect_tree_backref(struct btrfs_backref_cache *cache,
33153317
* If we know the block isn't shared we can avoid
33163318
* checking its backrefs.
33173319
*/
3318-
if (btrfs_block_can_be_shared(root, eb))
3320+
if (btrfs_block_can_be_shared(trans, root, eb))
33193321
upper->checked = 0;
33203322
else
33213323
upper->checked = 1;
@@ -3363,11 +3365,13 @@ static int handle_indirect_tree_backref(struct btrfs_backref_cache *cache,
33633365
* links aren't yet bi-directional. Needs to finish such links.
33643366
* Use btrfs_backref_finish_upper_links() to finish such linkage.
33653367
*
3368+
* @trans: Transaction handle.
33663369
* @path: Released path for indirect tree backref lookup
33673370
* @iter: Released backref iter for extent tree search
33683371
* @node_key: The first key of the tree block
33693372
*/
3370-
int btrfs_backref_add_tree_node(struct btrfs_backref_cache *cache,
3373+
int btrfs_backref_add_tree_node(struct btrfs_trans_handle *trans,
3374+
struct btrfs_backref_cache *cache,
33713375
struct btrfs_path *path,
33723376
struct btrfs_backref_iter *iter,
33733377
struct btrfs_key *node_key,
@@ -3467,8 +3471,8 @@ int btrfs_backref_add_tree_node(struct btrfs_backref_cache *cache,
34673471
* offset means the root objectid. We need to search
34683472
* the tree to get its parent bytenr.
34693473
*/
3470-
ret = handle_indirect_tree_backref(cache, path, &key, node_key,
3471-
cur);
3474+
ret = handle_indirect_tree_backref(trans, cache, path,
3475+
&key, node_key, cur);
34723476
if (ret < 0)
34733477
goto out;
34743478
}

fs/btrfs/backref.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,8 @@ static inline void btrfs_backref_panic(struct btrfs_fs_info *fs_info,
540540
bytenr);
541541
}
542542

543-
int btrfs_backref_add_tree_node(struct btrfs_backref_cache *cache,
543+
int btrfs_backref_add_tree_node(struct btrfs_trans_handle *trans,
544+
struct btrfs_backref_cache *cache,
544545
struct btrfs_path *path,
545546
struct btrfs_backref_iter *iter,
546547
struct btrfs_key *node_key,

fs/btrfs/ctree.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,8 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
367367
/*
368368
* check if the tree block can be shared by multiple trees
369369
*/
370-
int btrfs_block_can_be_shared(struct btrfs_root *root,
370+
int btrfs_block_can_be_shared(struct btrfs_trans_handle *trans,
371+
struct btrfs_root *root,
371372
struct extent_buffer *buf)
372373
{
373374
/*
@@ -376,11 +377,21 @@ int btrfs_block_can_be_shared(struct btrfs_root *root,
376377
* not allocated by tree relocation, we know the block is not shared.
377378
*/
378379
if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) &&
379-
buf != root->node && buf != root->commit_root &&
380+
buf != root->node &&
380381
(btrfs_header_generation(buf) <=
381382
btrfs_root_last_snapshot(&root->root_item) ||
382-
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)))
383-
return 1;
383+
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) {
384+
if (buf != root->commit_root)
385+
return 1;
386+
/*
387+
* An extent buffer that used to be the commit root may still be
388+
* shared because the tree height may have increased and it
389+
* became a child of a higher level root. This can happen when
390+
* snapshotting a subvolume created in the current transaction.
391+
*/
392+
if (btrfs_header_generation(buf) == trans->transid)
393+
return 1;
394+
}
384395

385396
return 0;
386397
}
@@ -415,7 +426,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
415426
* are only allowed for blocks use full backrefs.
416427
*/
417428

418-
if (btrfs_block_can_be_shared(root, buf)) {
429+
if (btrfs_block_can_be_shared(trans, root, buf)) {
419430
ret = btrfs_lookup_extent_info(trans, fs_info, buf->start,
420431
btrfs_header_level(buf), 1,
421432
&refs, &flags);

fs/btrfs/ctree.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,8 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
540540
struct btrfs_root *root,
541541
struct extent_buffer *buf,
542542
struct extent_buffer **cow_ret, u64 new_root_objectid);
543-
int btrfs_block_can_be_shared(struct btrfs_root *root,
543+
int btrfs_block_can_be_shared(struct btrfs_trans_handle *trans,
544+
struct btrfs_root *root,
544545
struct extent_buffer *buf);
545546
int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
546547
struct btrfs_path *path, int level, int slot);

fs/btrfs/relocation.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ static bool handle_useless_nodes(struct reloc_control *rc,
466466
* cached.
467467
*/
468468
static noinline_for_stack struct btrfs_backref_node *build_backref_tree(
469+
struct btrfs_trans_handle *trans,
469470
struct reloc_control *rc, struct btrfs_key *node_key,
470471
int level, u64 bytenr)
471472
{
@@ -499,8 +500,8 @@ static noinline_for_stack struct btrfs_backref_node *build_backref_tree(
499500

500501
/* Breadth-first search to build backref cache */
501502
do {
502-
ret = btrfs_backref_add_tree_node(cache, path, iter, node_key,
503-
cur);
503+
ret = btrfs_backref_add_tree_node(trans, cache, path, iter,
504+
node_key, cur);
504505
if (ret < 0) {
505506
err = ret;
506507
goto out;
@@ -2803,7 +2804,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans,
28032804

28042805
/* Do tree relocation */
28052806
rbtree_postorder_for_each_entry_safe(block, next, blocks, rb_node) {
2806-
node = build_backref_tree(rc, &block->key,
2807+
node = build_backref_tree(trans, rc, &block->key,
28072808
block->level, block->bytenr);
28082809
if (IS_ERR(node)) {
28092810
err = PTR_ERR(node);

0 commit comments

Comments
 (0)