fs/btrfs/free-space-tree.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
btrfs_rebuild_free_space_tree() sets
BTRFS_FS_CREATING_FREE_SPACE_TREE and
BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED before rebuilding the free space
tree. Several error paths return without clearing these flags.
This leaves the flags set on the live filesystem and affects delayed
reference processing and free-space caching. Clear both flags on all
free space tree rebuild failure paths.
Fixes: 1d6a4fc85717 ("btrfs: make clear_cache mount option to rebuild FST without disabling it")
Cc: stable@vger.kernel.org # 6.4+
Assisted-by: Codex:gpt-5
Tested: make -j$(nproc) fs/btrfs/free-space-tree.o
Signed-off-by: Guanghui Yang <3497809730@qq.com>
---
fs/btrfs/free-space-tree.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
index 1b3d82ae3de8..1410da2766a9 100644
--- a/fs/btrfs/free-space-tree.c
+++ b/fs/btrfs/free-space-tree.c
@@ -1353,7 +1353,7 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans);
- return ret;
+ goto out_clear;
}
node = rb_first_cached(&fs_info->block_group_cache_tree);
@@ -1371,14 +1371,16 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans);
- return ret;
+ goto out_clear;
}
next:
if (btrfs_should_end_transaction(trans)) {
btrfs_end_transaction(trans);
trans = btrfs_start_transaction(free_space_root, 1);
- if (IS_ERR(trans))
- return PTR_ERR(trans);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out_clear;
+ }
}
node = rb_next(node);
}
@@ -1390,6 +1392,11 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
ret = btrfs_commit_transaction(trans);
clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
return ret;
+
+out_clear:
+ clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
+ clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
+ return ret;
}
static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
base-commit: 587858367581b9c55c3690f4e63382ad622719d4
--
2.34.1
在 2026/9/16 00:18, Guanghui Yang 写道:
> btrfs_rebuild_free_space_tree() sets
> BTRFS_FS_CREATING_FREE_SPACE_TREE and
> BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED before rebuilding the free space
> tree. Several error paths return without clearing these flags.
>
> This leaves the flags set on the live filesystem and affects delayed
> reference processing and free-space caching.
What kind of effect?
> Clear both flags on all
> free space tree rebuild failure paths.
>
> Fixes: 1d6a4fc85717 ("btrfs: make clear_cache mount option to rebuild FST without disabling it")
> Cc: stable@vger.kernel.org # 6.4+
> Assisted-by: Codex:gpt-5
> Tested: make -j$(nproc) fs/btrfs/free-space-tree.o
That's not helpful, you should run the full fstests instead.
> Signed-off-by: Guanghui Yang <3497809730@qq.com>
> ---
> fs/btrfs/free-space-tree.c | 15 +++++++++++----
> 1 file changed, 11 insertions(+), 4 deletions(-)
>
> diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
> index 1b3d82ae3de8..1410da2766a9 100644
> --- a/fs/btrfs/free-space-tree.c
> +++ b/fs/btrfs/free-space-tree.c
> @@ -1353,7 +1353,7 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
> if (unlikely(ret)) {
> btrfs_abort_transaction(trans, ret);
> btrfs_end_transaction(trans);
> - return ret;
> + goto out_clear;
> }
>
> node = rb_first_cached(&fs_info->block_group_cache_tree);
> @@ -1371,14 +1371,16 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
> if (unlikely(ret)) {
> btrfs_abort_transaction(trans, ret);
> btrfs_end_transaction(trans);
> - return ret;
> + goto out_clear;
> }
> next:
> if (btrfs_should_end_transaction(trans)) {
> btrfs_end_transaction(trans);
> trans = btrfs_start_transaction(free_space_root, 1);
> - if (IS_ERR(trans))
> - return PTR_ERR(trans);
> + if (IS_ERR(trans)) {
> + ret = PTR_ERR(trans);
> + goto out_clear;
> + }
> }
> node = rb_next(node);
> }
> @@ -1390,6 +1392,11 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
> ret = btrfs_commit_transaction(trans);
> clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
> return ret;
> +
> +out_clear:
> + clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
> + clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
The free space tree is not properly rebuilt, thus we can not trust it
anymore.
Why you want to clear the UNTRUSTED flag?
> + return ret;
> }
>
> static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
>
> base-commit: 587858367581b9c55c3690f4e63382ad622719d4
On Tue, Sep 15, 2026 at 02:48:45PM +0000, Guanghui Yang wrote:
> btrfs_rebuild_free_space_tree() sets
> BTRFS_FS_CREATING_FREE_SPACE_TREE and
> BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED before rebuilding the free space
> tree. Several error paths return without clearing these flags.
>
> This leaves the flags set on the live filesystem and affects delayed
> reference processing and free-space caching. Clear both flags on all
> free space tree rebuild failure paths.
>
> Fixes: 1d6a4fc85717 ("btrfs: make clear_cache mount option to rebuild FST without disabling it")
I don't think this fixes tag is correct. In that version of the code,
all error paths aborted the transaction at which point the bit being set
or not doesn't really matter, in my opinion.
Unless I am missing something about the importance of clearing the bit
on an aborted transaction, I think the better fixes tag is:
882af9f13e83 ("btrfs: handle free space tree rebuild in multiple transactions")
> Cc: stable@vger.kernel.org # 6.4+
> Assisted-by: Codex:gpt-5
> Tested: make -j$(nproc) fs/btrfs/free-space-tree.o
Is this all the testing you did or did you also run fstests on this
change?
Generally looks like a good fix for start_transaction() errors, though.
Thanks,
Boris
btrfs_rebuild_free_space_tree() sets
BTRFS_FS_CREATING_FREE_SPACE_TREE before rebuilding the free space tree.
Several error paths return without clearing this flag.
The transaction restart failure path can leave the flag set on a live
filesystem, causing delayed reference processing to be skipped. Clear it
on all free space tree rebuild failure paths. Keep
BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED set, since a failed rebuild leaves the
free space tree untrusted. Callers must fall back to extent-tree caching.
Fixes: 882af9f13e83 ("btrfs: handle free space tree rebuild in multiple transactions")
Cc: stable@vger.kernel.org # 6.14+
Assisted-by: Codex:gpt-5
Tested: make -j$(nproc) fs/btrfs/free-space-tree.o
Signed-off-by: Guanghui Yang <3497809730@qq.com>
---
fs/btrfs/free-space-tree.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
index 1b3d82ae3de8..b7a4a6ade30f 100644
--- a/fs/btrfs/free-space-tree.c
+++ b/fs/btrfs/free-space-tree.c
@@ -1353,7 +1353,7 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans);
- return ret;
+ goto out_clear;
}
node = rb_first_cached(&fs_info->block_group_cache_tree);
@@ -1371,14 +1371,16 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans);
- return ret;
+ goto out_clear;
}
next:
if (btrfs_should_end_transaction(trans)) {
btrfs_end_transaction(trans);
trans = btrfs_start_transaction(free_space_root, 1);
- if (IS_ERR(trans))
- return PTR_ERR(trans);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out_clear;
+ }
}
node = rb_next(node);
}
@@ -1390,6 +1392,10 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
ret = btrfs_commit_transaction(trans);
clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
return ret;
+
+out_clear:
+ clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
+ return ret;
}
static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
base-commit: 587858367581b9c55c3690f4e63382ad622719d4
--
2.34.1
在 2026/9/16 12:08, Guanghui Yang 写道:
> btrfs_rebuild_free_space_tree() sets
> BTRFS_FS_CREATING_FREE_SPACE_TREE before rebuilding the free space tree.
> Several error paths return without clearing this flag.
>
> The transaction restart failure path can leave the flag set on a live
> filesystem, causing delayed reference processing to be skipped. Clear it
> on all free space tree rebuild failure paths. Keep
> BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED set, since a failed rebuild leaves the
> free space tree untrusted. Callers must fall back to extent-tree caching.
>
> Fixes: 882af9f13e83 ("btrfs: handle free space tree rebuild in multiple transactions")
> Cc: stable@vger.kernel.org # 6.14+
> Assisted-by: Codex:gpt-5
> Tested: make -j$(nproc) fs/btrfs/free-space-tree.o
Just remove the useless tag, and run a proper full fstests.
> Signed-off-by: Guanghui Yang <3497809730@qq.com>
> ---
> fs/btrfs/free-space-tree.c | 14 ++++++++++----
> 1 file changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
> index 1b3d82ae3de8..b7a4a6ade30f 100644
> --- a/fs/btrfs/free-space-tree.c
> +++ b/fs/btrfs/free-space-tree.c
> @@ -1353,7 +1353,7 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
> if (unlikely(ret)) {
> btrfs_abort_transaction(trans, ret);
> btrfs_end_transaction(trans);
> - return ret;
> + goto out_clear;
> }
>
> node = rb_first_cached(&fs_info->block_group_cache_tree);
> @@ -1371,14 +1371,16 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
> if (unlikely(ret)) {
> btrfs_abort_transaction(trans, ret);
> btrfs_end_transaction(trans);
> - return ret;
> + goto out_clear;
> }
> next:
> if (btrfs_should_end_transaction(trans)) {
> btrfs_end_transaction(trans);
> trans = btrfs_start_transaction(free_space_root, 1);
> - if (IS_ERR(trans))
> - return PTR_ERR(trans);
> + if (IS_ERR(trans)) {
> + ret = PTR_ERR(trans);
> + goto out_clear;
> + }
> }
> node = rb_next(node);
> }
> @@ -1390,6 +1392,10 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
> ret = btrfs_commit_transaction(trans);
> clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
> return ret;
> +
> +out_clear:
> + clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
> + return ret;
> }
>
> static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
>
> base-commit: 587858367581b9c55c3690f4e63382ad622719d4
btrfs_rebuild_free_space_tree() sets
BTRFS_FS_CREATING_FREE_SPACE_TREE before rebuilding the free space tree.
Several error paths return without clearing this flag.
The transaction restart failure path can leave the flag set on a live
filesystem, causing delayed reference processing to be skipped. Clear it
on all free space tree rebuild failure paths. Keep
BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED set, since a failed rebuild leaves the
free space tree untrusted. Callers must fall back to extent-tree caching.
Fixes: 882af9f13e83 ("btrfs: handle free space tree rebuild in multiple transactions")
Cc: stable@vger.kernel.org # 6.14+
Tested:
xfstests btrfs/015 btrfs/032 btrfs/104 btrfs/131 btrfs/352 (pass)
xfstests btrfs/quick: 261 passed, 30 failed, 90 not run on
Ubuntu 5.15.0-60-generic
Assisted-by: LLM
Signed-off-by: Guanghui Yang <3497809730@qq.com>
---
fs/btrfs/free-space-tree.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
index 1b3d82ae3de8..b7a4a6ade30f 100644
--- a/fs/btrfs/free-space-tree.c
+++ b/fs/btrfs/free-space-tree.c
@@ -1353,7 +1353,7 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans);
- return ret;
+ goto out_clear;
}
node = rb_first_cached(&fs_info->block_group_cache_tree);
@@ -1371,14 +1371,16 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans);
- return ret;
+ goto out_clear;
}
next:
if (btrfs_should_end_transaction(trans)) {
btrfs_end_transaction(trans);
trans = btrfs_start_transaction(free_space_root, 1);
- if (IS_ERR(trans))
- return PTR_ERR(trans);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out_clear;
+ }
}
node = rb_next(node);
}
@@ -1390,6 +1392,10 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
ret = btrfs_commit_transaction(trans);
clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
return ret;
+
+out_clear:
+ clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
+ return ret;
}
static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
base-commit: 587858367581b9c55c3690f4e63382ad622719d4
--
2.34.1
On Wed, Sep 16, 2026 at 05:16:38AM +0000, Guanghui Yang wrote:
> btrfs_rebuild_free_space_tree() sets
> BTRFS_FS_CREATING_FREE_SPACE_TREE before rebuilding the free space tree.
> Several error paths return without clearing this flag.
>
> The transaction restart failure path can leave the flag set on a live
> filesystem, causing delayed reference processing to be skipped. Clear it
> on all free space tree rebuild failure paths. Keep
> BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED set, since a failed rebuild leaves the
> free space tree untrusted. Callers must fall back to extent-tree caching.
>
> Fixes: 882af9f13e83 ("btrfs: handle free space tree rebuild in multiple transactions")
> Cc: stable@vger.kernel.org # 6.14+
> Tested:
> xfstests btrfs/015 btrfs/032 btrfs/104 btrfs/131 btrfs/352 (pass)
> xfstests btrfs/quick: 261 passed, 30 failed, 90 not run on
> Ubuntu 5.15.0-60-generic
> Assisted-by: LLM
Reviewed-by: Boris Burkov <boris@bur.io>
> Signed-off-by: Guanghui Yang <3497809730@qq.com>
> ---
> fs/btrfs/free-space-tree.c | 14 ++++++++++----
> 1 file changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
> index 1b3d82ae3de8..b7a4a6ade30f 100644
> --- a/fs/btrfs/free-space-tree.c
> +++ b/fs/btrfs/free-space-tree.c
> @@ -1353,7 +1353,7 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
> if (unlikely(ret)) {
> btrfs_abort_transaction(trans, ret);
> btrfs_end_transaction(trans);
> - return ret;
> + goto out_clear;
> }
>
> node = rb_first_cached(&fs_info->block_group_cache_tree);
> @@ -1371,14 +1371,16 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
> if (unlikely(ret)) {
> btrfs_abort_transaction(trans, ret);
> btrfs_end_transaction(trans);
> - return ret;
> + goto out_clear;
> }
> next:
> if (btrfs_should_end_transaction(trans)) {
> btrfs_end_transaction(trans);
> trans = btrfs_start_transaction(free_space_root, 1);
> - if (IS_ERR(trans))
> - return PTR_ERR(trans);
> + if (IS_ERR(trans)) {
> + ret = PTR_ERR(trans);
> + goto out_clear;
> + }
> }
> node = rb_next(node);
> }
> @@ -1390,6 +1392,10 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
> ret = btrfs_commit_transaction(trans);
> clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
> return ret;
> +
> +out_clear:
> + clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
> + return ret;
> }
>
> static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
>
> base-commit: 587858367581b9c55c3690f4e63382ad622719d4
> --
> 2.34.1
>
在 2026/9/16 14:46, Guanghui Yang 写道:
> btrfs_rebuild_free_space_tree() sets
> BTRFS_FS_CREATING_FREE_SPACE_TREE before rebuilding the free space tree.
> Several error paths return without clearing this flag.
>
> The transaction restart failure path can leave the flag set on a live
> filesystem, causing delayed reference processing to be skipped. Clear it
> on all free space tree rebuild failure paths. Keep
> BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED set, since a failed rebuild leaves the
> free space tree untrusted. Callers must fall back to extent-tree caching.
>
> Fixes: 882af9f13e83 ("btrfs: handle free space tree rebuild in multiple transactions")
> Cc: stable@vger.kernel.org # 6.14+
> Tested:
> xfstests btrfs/015 btrfs/032 btrfs/104 btrfs/131 btrfs/352 (pass)
> xfstests btrfs/quick: 261 passed, 30 failed, 90 not run on
> Ubuntu 5.15.0-60-generic
WTF? You're not even running the tests with an upstream kernel with your
patch applied?
Thankfully the patch still looks good to me.
Reviewed-by: Qu Wenruo <wqu@suse.com>
I'll remove the stupid tag, and finally stop wasting time on someone who
doesn't have any brain cell to properly test the patch.
> Assisted-by: LLM
> Signed-off-by: Guanghui Yang <3497809730@qq.com>
> ---
> fs/btrfs/free-space-tree.c | 14 ++++++++++----
> 1 file changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
> index 1b3d82ae3de8..b7a4a6ade30f 100644
> --- a/fs/btrfs/free-space-tree.c
> +++ b/fs/btrfs/free-space-tree.c
> @@ -1353,7 +1353,7 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
> if (unlikely(ret)) {
> btrfs_abort_transaction(trans, ret);
> btrfs_end_transaction(trans);
> - return ret;
> + goto out_clear;
> }
>
> node = rb_first_cached(&fs_info->block_group_cache_tree);
> @@ -1371,14 +1371,16 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
> if (unlikely(ret)) {
> btrfs_abort_transaction(trans, ret);
> btrfs_end_transaction(trans);
> - return ret;
> + goto out_clear;
> }
> next:
> if (btrfs_should_end_transaction(trans)) {
> btrfs_end_transaction(trans);
> trans = btrfs_start_transaction(free_space_root, 1);
> - if (IS_ERR(trans))
> - return PTR_ERR(trans);
> + if (IS_ERR(trans)) {
> + ret = PTR_ERR(trans);
> + goto out_clear;
> + }
> }
> node = rb_next(node);
> }
> @@ -1390,6 +1392,10 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
> ret = btrfs_commit_transaction(trans);
> clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
> return ret;
> +
> +out_clear:
> + clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
> + return ret;
> }
>
> static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
>
> base-commit: 587858367581b9c55c3690f4e63382ad622719d4
© 2016 - 2026 Red Hat, Inc.