* [PATCH 0/3] btrfs-progs: add repair support to delete orphan
@ 2026-02-05 23:59 Qu Wenruo
2026-02-05 23:59 ` [PATCH 1/3] btrfs-progs: check: report all orphan free space info keys Qu Wenruo
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Qu Wenruo @ 2026-02-05 23:59 UTC (permalink / raw)
To: linux-btrfs
This is the same PR in github:
https://github.com/kdave/btrfs-progs/pull/1083
The mail thread is mostly for tracking and review purposes.
Since v6.16.1 btrfs check adds the ability to detect orphan free space
entries, and older mkfs.btrfs forgot to delete free space entries of
temporary chunks, which can be detected by newer btrfs-progs now.
Although we're already pushing for a kernel auto fix, the kernel fix
will take some time to reach upstream, and more time to reach distros.
So there is still some value to have the repair ability in btrfs-check.
Furthermore, the new repair ability is more flex than the kernel one,
which can handle orphan free space info key, not only the ones exposed
by the recent btrfs-check.
Although only the recent exposed one is tested.
Qu Wenruo (3):
btrfs-progs: check: report all orphan free space info keys
btrfs-progs: check: add repair support for orphan fst entry
btrfs-progs: fsck-tests: add a new test case for deleting orphan fst
entries
common/clear-cache.c | 141 +++++++++++++++++-
.../071-orphan-fst-entry/.lowmem_repairable | 0
.../orphan_fst_entries.img.xz | Bin 0 -> 1864 bytes
3 files changed, 137 insertions(+), 4 deletions(-)
create mode 100644 tests/fsck-tests/071-orphan-fst-entry/.lowmem_repairable
create mode 100644 tests/fsck-tests/071-orphan-fst-entry/orphan_fst_entries.img.xz
--
2.52.0
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH 1/3] btrfs-progs: check: report all orphan free space info keys 2026-02-05 23:59 [PATCH 0/3] btrfs-progs: add repair support to delete orphan Qu Wenruo @ 2026-02-05 23:59 ` Qu Wenruo 2026-02-05 23:59 ` [PATCH 2/3] btrfs-progs: check: add repair support for orphan fst entry Qu Wenruo 2026-02-05 23:59 ` [PATCH 3/3] btrfs-progs: fsck-tests: add a new test case for deleting orphan fst entries Qu Wenruo 2 siblings, 0 replies; 4+ messages in thread From: Qu Wenruo @ 2026-02-05 23:59 UTC (permalink / raw) To: linux-btrfs And also output the logical and length for the orphan space info key. Now the new reports will looks like this: [4/8] checking free space tree Space key logical 1048576 length 4194304 has no corresponding block group Space key logical 5242880 length 8388608 has no corresponding block group This shouldn't affect end users that much, but provide much better debug info for developers who want to fix those bad free space tree entries. Signed-off-by: Qu Wenruo <wqu@suse.com> --- common/clear-cache.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/common/clear-cache.c b/common/clear-cache.c index 75cd8d50d25a..47d5751ff2c9 100644 --- a/common/clear-cache.c +++ b/common/clear-cache.c @@ -138,6 +138,7 @@ static int check_free_space_tree(struct btrfs_root *root) struct btrfs_key key = { 0 }; struct btrfs_path path = { 0 }; int ret = 0; + bool found_orphan = false; while (1) { struct btrfs_block_group *bg; @@ -167,16 +168,19 @@ static int check_free_space_tree(struct btrfs_root *root) bg = btrfs_lookup_block_group(fs_info, key.objectid); if (!bg) { fprintf(stderr, - "We have a space info key for a block group that doesn't exist\n"); - ret = -EINVAL; - goto out; +"Space key logical %llu length %llu has no corresponding block group\n", + key.objectid, key.offset); + found_orphan = true; } btrfs_release_path(&path); key.objectid += key.offset; key.offset = 0; } - ret = 0; + if (found_orphan) + ret = -EINVAL; + else + ret = 0; out: btrfs_release_path(&path); return ret; -- 2.52.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/3] btrfs-progs: check: add repair support for orphan fst entry 2026-02-05 23:59 [PATCH 0/3] btrfs-progs: add repair support to delete orphan Qu Wenruo 2026-02-05 23:59 ` [PATCH 1/3] btrfs-progs: check: report all orphan free space info keys Qu Wenruo @ 2026-02-05 23:59 ` Qu Wenruo 2026-02-05 23:59 ` [PATCH 3/3] btrfs-progs: fsck-tests: add a new test case for deleting orphan fst entries Qu Wenruo 2 siblings, 0 replies; 4+ messages in thread From: Qu Wenruo @ 2026-02-05 23:59 UTC (permalink / raw) To: linux-btrfs Although we're pushing for the kernel auto fix, it may still take some time. Meanwhile having a proper way to fix it in progs will never hurt. The repair itself is a little more complex than the kernel one, which only needs to bother the entries before the first block group. This progs version in theory is able to handle orphan entries at any location, but for now it's only for the entries before the first bg. Signed-off-by: Qu Wenruo <wqu@suse.com> --- common/clear-cache.c | 131 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 1 deletion(-) diff --git a/common/clear-cache.c b/common/clear-cache.c index 47d5751ff2c9..69e91e5e7796 100644 --- a/common/clear-cache.c +++ b/common/clear-cache.c @@ -29,6 +29,7 @@ #include "kernel-shared/volumes.h" #include "kernel-shared/transaction.h" #include "kernel-shared/file-item.h" +#include "kernel-shared/print-tree.h" #include "common/internal.h" #include "common/messages.h" #include "common/clear-cache.h" @@ -132,6 +133,128 @@ close_out: return ret; } +/* + * Return 0 if we found an fst entry in range [start, start + length), @path will + * be updated to pointing to that entry. + * + * Return >0 if we found no more fst entry in range [start, start + length). + * + * Return <0 for error. + */ +static int find_first_fst_entry(struct btrfs_root *root, struct btrfs_path *path, + u64 start, u64 length) +{ + struct btrfs_key key = { .objectid = start }; + int ret; + + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (unlikely(ret < 0)) + goto out; + if (unlikely(ret == 0)) { + ret = -EUCLEAN; + error("unexpected key found in slot %u\n", path->slots[0]); + btrfs_print_leaf(path->nodes[0]); + goto out; + } + while (true) { + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + ret = btrfs_next_leaf(root, path); + if (ret) + goto out; + } + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + /* Beyond the range. No more entry. */ + if (key.objectid >= start + length) { + ret = 1; + goto out; + } + /* In the range, return this one. */ + if (key.objectid >= start && key.objectid < start + length) + break; + + /* The current key is small than our range, continue searching. */ + path->slots[0]++; + } + + /* We found a key in our range. */ + UASSERT(path->nodes[0]); + return 0; +out: + UASSERT(ret != 0); + btrfs_release_path(path); + return ret; +} + +static int remove_free_space_entries(struct btrfs_root *root, struct btrfs_path *path, + const struct btrfs_key *space_info_key) +{ + struct btrfs_trans_handle *trans = NULL; + u64 start = space_info_key->objectid; + const u64 end = start + space_info_key->offset - 1; + u64 cur = start; + int ret; + + while (cur <= end) { + struct btrfs_key found_key; + int found_slot; + int last_slot; + + ret = find_first_fst_entry(root, path, cur, end + 1 - cur); + if (ret < 0) + goto error; + if (ret > 0) + break; + + btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); + btrfs_release_path(path); + + trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + error_msg(ERROR_MSG_START_TRANS, "remove orphan fst entry"); + return PTR_ERR(trans); + } + ret = btrfs_search_slot(trans, root, &found_key, path, -1, 1); + if (ret > 0) + ret = -ENOENT; + if (ret < 0) + goto error; + + found_slot = path->slots[0]; + + /* + * @last_slot will be the next slot of the last item which matches + * our range. + */ + for (last_slot = found_slot + 1; + last_slot < btrfs_header_nritems(path->nodes[0]); last_slot++){ + btrfs_item_key_to_cpu(path->nodes[0], &found_key, last_slot); + if (found_key.objectid >= start && found_key.objectid <= end) + cur = found_key.objectid; + else + break; + } + ret = btrfs_del_items(trans, root, path, found_slot, + last_slot - found_slot); + if (ret < 0) + goto error; + btrfs_release_path(path); + ret = btrfs_commit_transaction(trans, root); + trans = NULL; + if (ret < 0) { + error_msg(ERROR_MSG_START_TRANS, "remove orphan fst entry"); + goto error; + } + } + printf("deleted orphan fst entries for range [%llu, %llu)\n", + start, end + 1); + return 0; +error: + btrfs_release_path(path); + if (trans) + btrfs_abort_transaction(trans, ret); + return ret; +} + static int check_free_space_tree(struct btrfs_root *root) { struct btrfs_fs_info *fs_info = root->fs_info; @@ -167,10 +290,16 @@ static int check_free_space_tree(struct btrfs_root *root) bg = btrfs_lookup_block_group(fs_info, key.objectid); if (!bg) { + btrfs_release_path(&path); fprintf(stderr, "Space key logical %llu length %llu has no corresponding block group\n", key.objectid, key.offset); - found_orphan = true; + if (opt_check_repair) + ret = remove_free_space_entries(root, &path, &key); + else + ret = -EINVAL; + if (ret < 0) + found_orphan = true; } btrfs_release_path(&path); -- 2.52.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 3/3] btrfs-progs: fsck-tests: add a new test case for deleting orphan fst entries 2026-02-05 23:59 [PATCH 0/3] btrfs-progs: add repair support to delete orphan Qu Wenruo 2026-02-05 23:59 ` [PATCH 1/3] btrfs-progs: check: report all orphan free space info keys Qu Wenruo 2026-02-05 23:59 ` [PATCH 2/3] btrfs-progs: check: add repair support for orphan fst entry Qu Wenruo @ 2026-02-05 23:59 ` Qu Wenruo 2 siblings, 0 replies; 4+ messages in thread From: Qu Wenruo @ 2026-02-05 23:59 UTC (permalink / raw) To: linux-btrfs The image is created by creating an empty btrfs with older v6.16 btrfs-progs. Which has free space tree entries for two temporary block groups. And the test itself is going through the common repair test procedure. Signed-off-by: Qu Wenruo <wqu@suse.com> --- .../071-orphan-fst-entry/.lowmem_repairable | 0 .../orphan_fst_entries.img.xz | Bin 0 -> 1864 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/fsck-tests/071-orphan-fst-entry/.lowmem_repairable create mode 100644 tests/fsck-tests/071-orphan-fst-entry/orphan_fst_entries.img.xz diff --git a/tests/fsck-tests/071-orphan-fst-entry/.lowmem_repairable b/tests/fsck-tests/071-orphan-fst-entry/.lowmem_repairable new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/fsck-tests/071-orphan-fst-entry/orphan_fst_entries.img.xz b/tests/fsck-tests/071-orphan-fst-entry/orphan_fst_entries.img.xz new file mode 100644 index 0000000000000000000000000000000000000000..bc68661b1e1917da5266c50747e6c7f14cfecf49 GIT binary patch literal 1864 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 literal 0 HcmV?d00001 -- 2.52.0 ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-02-06 0:00 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-02-05 23:59 [PATCH 0/3] btrfs-progs: add repair support to delete orphan Qu Wenruo 2026-02-05 23:59 ` [PATCH 1/3] btrfs-progs: check: report all orphan free space info keys Qu Wenruo 2026-02-05 23:59 ` [PATCH 2/3] btrfs-progs: check: add repair support for orphan fst entry Qu Wenruo 2026-02-05 23:59 ` [PATCH 3/3] btrfs-progs: fsck-tests: add a new test case for deleting orphan fst entries Qu Wenruo
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox