for-6.6-rc7-tag
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAmU2lLEACgkQxWXV+ddt WDvCThAApe+zMNdEhQ/cgrvfzP/X91Q53PXQsdVsrujPyUV8eEV4oJzEwVbJhRdw 3ukIQtvyAMNiWhEBhOQRwxjuUoTCApGAeEEEl1cWWEqQ7G2/2LS4+bcWzgQ3Vu32 dzYL37ddsfe4n7OgfnymtMrnv7kge0XbAlY3GbavaDccZDQDqcD5wSAOyOhfIsH7 kcu4sA5Fi44wVSfAJX1Dms+wXfsmQu/sd3c9Gcyce9Hpy1cEW3vWbApLBE4K0aKX /JHTdmkAJ20a4APQsfGH+UymyuZgr8d2eGmL9rVYKhT/c+Dow0lNAWYkvGf/MawM CX3GdP6f6ZOR/anCPZ8nqZCE5AoFykGazvpCCSrvCOpU7o7GqxbAQkWWFcMp1FHW 9TFrj81WK18DeCfCNw7lR3sdMy/2o2nnSUAw3DFY4n/3Lek7FUmrBTHvXlWDot7T TM9CzYGF840QhL5s5SMYS09YmeI0I34L7HJAi/+qli48SooGuL9RZ29TmzHIX69Y 2bgpS64j06p/AGEnfHAcT1LbpiFCPmO5cpXKv/t40GL5QO5d4WV698ysDGoPYUPO 8CPL85Y8cao56KGJLyOroGz0P1bo+RdNe5bN6xJJoTRn1Y9oUA+bQSnN8x9iuunF 9QZrAIHzNyDcRGzoqgDW+3bivOvIus/Dto/u1P3ap68kP2HTVsY= =gOyi -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
e017769f4c
|
@ -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
|
* We still need to do a tree search to find out the parents. This is for
|
||||||
* TREE_BLOCK_REF backref (keyed or inlined).
|
* TREE_BLOCK_REF backref (keyed or inlined).
|
||||||
*
|
*
|
||||||
|
* @trans: Transaction handle.
|
||||||
* @ref_key: The same as @ref_key in handle_direct_tree_backref()
|
* @ref_key: The same as @ref_key in handle_direct_tree_backref()
|
||||||
* @tree_key: The first key of this tree block.
|
* @tree_key: The first key of this tree block.
|
||||||
* @path: A clean (released) path, to avoid allocating path every time
|
* @path: A clean (released) path, to avoid allocating path every time
|
||||||
* the function get called.
|
* 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_path *path,
|
||||||
struct btrfs_key *ref_key,
|
struct btrfs_key *ref_key,
|
||||||
struct btrfs_key *tree_key,
|
struct btrfs_key *tree_key,
|
||||||
|
@ -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
|
* If we know the block isn't shared we can avoid
|
||||||
* checking its backrefs.
|
* checking its backrefs.
|
||||||
*/
|
*/
|
||||||
if (btrfs_block_can_be_shared(root, eb))
|
if (btrfs_block_can_be_shared(trans, root, eb))
|
||||||
upper->checked = 0;
|
upper->checked = 0;
|
||||||
else
|
else
|
||||||
upper->checked = 1;
|
upper->checked = 1;
|
||||||
|
@ -3363,11 +3365,13 @@ out:
|
||||||
* links aren't yet bi-directional. Needs to finish such links.
|
* links aren't yet bi-directional. Needs to finish such links.
|
||||||
* Use btrfs_backref_finish_upper_links() to finish such linkage.
|
* Use btrfs_backref_finish_upper_links() to finish such linkage.
|
||||||
*
|
*
|
||||||
|
* @trans: Transaction handle.
|
||||||
* @path: Released path for indirect tree backref lookup
|
* @path: Released path for indirect tree backref lookup
|
||||||
* @iter: Released backref iter for extent tree search
|
* @iter: Released backref iter for extent tree search
|
||||||
* @node_key: The first key of the tree block
|
* @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_path *path,
|
||||||
struct btrfs_backref_iter *iter,
|
struct btrfs_backref_iter *iter,
|
||||||
struct btrfs_key *node_key,
|
struct btrfs_key *node_key,
|
||||||
|
@ -3467,8 +3471,8 @@ int btrfs_backref_add_tree_node(struct btrfs_backref_cache *cache,
|
||||||
* offset means the root objectid. We need to search
|
* offset means the root objectid. We need to search
|
||||||
* the tree to get its parent bytenr.
|
* the tree to get its parent bytenr.
|
||||||
*/
|
*/
|
||||||
ret = handle_indirect_tree_backref(cache, path, &key, node_key,
|
ret = handle_indirect_tree_backref(trans, cache, path,
|
||||||
cur);
|
&key, node_key, cur);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -540,7 +540,8 @@ static inline void btrfs_backref_panic(struct btrfs_fs_info *fs_info,
|
||||||
bytenr);
|
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_path *path,
|
||||||
struct btrfs_backref_iter *iter,
|
struct btrfs_backref_iter *iter,
|
||||||
struct btrfs_key *node_key,
|
struct btrfs_key *node_key,
|
||||||
|
|
|
@ -367,7 +367,8 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
|
||||||
/*
|
/*
|
||||||
* check if the tree block can be shared by multiple trees
|
* 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)
|
struct extent_buffer *buf)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -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.
|
* not allocated by tree relocation, we know the block is not shared.
|
||||||
*/
|
*/
|
||||||
if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) &&
|
if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) &&
|
||||||
buf != root->node && buf != root->commit_root &&
|
buf != root->node &&
|
||||||
(btrfs_header_generation(buf) <=
|
(btrfs_header_generation(buf) <=
|
||||||
btrfs_root_last_snapshot(&root->root_item) ||
|
btrfs_root_last_snapshot(&root->root_item) ||
|
||||||
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)))
|
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) {
|
||||||
return 1;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -415,7 +426,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
|
||||||
* are only allowed for blocks use full backrefs.
|
* 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,
|
ret = btrfs_lookup_extent_info(trans, fs_info, buf->start,
|
||||||
btrfs_header_level(buf), 1,
|
btrfs_header_level(buf), 1,
|
||||||
&refs, &flags);
|
&refs, &flags);
|
||||||
|
|
|
@ -540,7 +540,8 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct extent_buffer *buf,
|
struct extent_buffer *buf,
|
||||||
struct extent_buffer **cow_ret, u64 new_root_objectid);
|
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);
|
struct extent_buffer *buf);
|
||||||
int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||||
struct btrfs_path *path, int level, int slot);
|
struct btrfs_path *path, int level, int slot);
|
||||||
|
|
|
@ -466,6 +466,7 @@ static bool handle_useless_nodes(struct reloc_control *rc,
|
||||||
* cached.
|
* cached.
|
||||||
*/
|
*/
|
||||||
static noinline_for_stack struct btrfs_backref_node *build_backref_tree(
|
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,
|
struct reloc_control *rc, struct btrfs_key *node_key,
|
||||||
int level, u64 bytenr)
|
int level, u64 bytenr)
|
||||||
{
|
{
|
||||||
|
@ -499,8 +500,8 @@ static noinline_for_stack struct btrfs_backref_node *build_backref_tree(
|
||||||
|
|
||||||
/* Breadth-first search to build backref cache */
|
/* Breadth-first search to build backref cache */
|
||||||
do {
|
do {
|
||||||
ret = btrfs_backref_add_tree_node(cache, path, iter, node_key,
|
ret = btrfs_backref_add_tree_node(trans, cache, path, iter,
|
||||||
cur);
|
node_key, cur);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
err = ret;
|
err = ret;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -2803,7 +2804,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
/* Do tree relocation */
|
/* Do tree relocation */
|
||||||
rbtree_postorder_for_each_entry_safe(block, next, blocks, rb_node) {
|
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);
|
block->level, block->bytenr);
|
||||||
if (IS_ERR(node)) {
|
if (IS_ERR(node)) {
|
||||||
err = PTR_ERR(node);
|
err = PTR_ERR(node);
|
||||||
|
|
Loading…
Reference in New Issue