* [PATCH v3 0/4] btrfs: fix balance NULL derefs and chunk/bg mapping verification
@ 2026-03-25 0:43 ZhengYuan Huang
2026-03-25 0:43 ` [PATCH v3 1/4] btrfs: balance: fix null-ptr-deref in chunk_usage_filter ZhengYuan Huang
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: ZhengYuan Huang @ 2026-03-25 0:43 UTC (permalink / raw)
To: dsterba, clm, idryomov
Cc: linux-btrfs, linux-kernel, baijiaju1990, r33s3n6, zzzccc427,
ZhengYuan Huang
This series fixes three NULL dereferences in btrfs balance paths and the
underlying mount-time verification bug that lets the corresponding
chunk/block-group inconsistency go undetected.
The balance crashes happen when metadata corruption leaves a chunk present
in the chunk tree but without a corresponding block group in the in-memory
block group cache. In that case, balance reaches code paths that call
btrfs_lookup_block_group() and dereference the returned pointer without
checking for NULL.
The first three patches harden the affected balance paths:
- patch 1 fixes chunk_usage_filter()
- patch 2 fixes chunk_usage_range_filter()
- patch 3 fixes btrfs_may_alloc_data_chunk()
They are kept separate because the affected code was introduced by
different commits, which should also make backporting easier, as
suggested by Qu Wenruo.
The fourth patch fixes the mount-time verification side. Based on David
Sterba's feedback, it now explicitly relies on the mount-time context and
uses a lockless traversal of mapping_tree. check_chunk_block_group_mappings()
is supposed to verify that every chunk has a matching block group, but its
current iteration starts with btrfs_find_chunk_map(fs_info, 0, 1). If no
chunk contains logical address 0, the lookup returns NULL immediately and
the loop exits without checking any chunk at all. As a result, the
corrupted mapping can survive mount and only crash later when balance
reaches it.
This series makes btrfs reject the inconsistency earlier at mount time,
and also hardens the balance paths so the corruption is reported as
-EUCLEAN instead of triggering NULL dereferences.
[CHANGELOG]
v3:
- added a new patch to fix the same missing-block-group NULL dereference
in btrfs_may_alloc_data_chunk()
- patch 1 and 2:
- changed the bool return flow to explicit int error propagation
- used ret2 for the nested filter return value in should_balance_chunk()
- patch 4:
- reworked the changelog based on David Sterba's feedback
- clarified the mount-time context for the lockless mapping_tree traversal
v2:
- split the two balance filter fixes into separate patches
- reworked the chunk/block-group verification fix so the last patch
addresses the case where check_chunk_block_group_mappings() does not
actually iterate all chunk mappings
ZhengYuan Huang (4):
btrfs: balance: fix null-ptr-deref in chunk_usage_filter
btrfs: balance: fix null-ptr-deref in chunk_usage_range_filter
btrfs: balance: fix null-ptr-deref in btrfs_may_alloc_data_chunk
btrfs: fix check_chunk_block_group_mappings() to iterate all chunk maps
fs/btrfs/block-group.c | 24 ++++++----------
fs/btrfs/volumes.c | 63 ++++++++++++++++++++++++++++++------------
2 files changed, 55 insertions(+), 32 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 1/4] btrfs: balance: fix null-ptr-deref in chunk_usage_filter
2026-03-25 0:43 [PATCH v3 0/4] btrfs: fix balance NULL derefs and chunk/bg mapping verification ZhengYuan Huang
@ 2026-03-25 0:43 ` ZhengYuan Huang
2026-03-25 0:43 ` [PATCH v3 2/4] btrfs: balance: fix null-ptr-deref in chunk_usage_range_filter ZhengYuan Huang
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: ZhengYuan Huang @ 2026-03-25 0:43 UTC (permalink / raw)
To: dsterba, clm, idryomov
Cc: linux-btrfs, linux-kernel, baijiaju1990, r33s3n6, zzzccc427,
ZhengYuan Huang
[BUG]
Running btrfs balance with a usage filter (-dusage=N) can trigger a
null-ptr-deref when metadata corruption causes a chunk to have no
corresponding block group in the in-memory cache:
KASAN: null-ptr-deref in range [0x0000000000000070-0x0000000000000077]
RIP: 0010:chunk_usage_filter fs/btrfs/volumes.c:3874 [inline]
RIP: 0010:should_balance_chunk fs/btrfs/volumes.c:4018 [inline]
RIP: 0010:__btrfs_balance fs/btrfs/volumes.c:4172 [inline]
RIP: 0010:btrfs_balance+0x2024/0x42b0 fs/btrfs/volumes.c:4604
...
Call Trace:
btrfs_ioctl_balance fs/btrfs/ioctl.c:3577 [inline]
btrfs_ioctl+0x25cf/0x5b90 fs/btrfs/ioctl.c:5313
vfs_ioctl fs/ioctl.c:51 [inline]
...
The bug is reproducible on next-20260312.
[CAUSE]
Two separate data structures are involved:
1. The on-disk chunk tree, which records every chunk (logical address
space region) and is iterated by __btrfs_balance().
2. The in-memory block group cache (fs_info->block_group_cache_tree),
which is built at mount time by btrfs_read_block_groups() and holds
a struct btrfs_block_group for each chunk. This cache is what the
usage filter queries.
On a well-formed filesystem, these two are kept in 1:1 correspondence.
However, btrfs_read_block_groups() builds the cache from block group
items in the extent tree, not directly from the chunk tree. A corrupted
image can therefore contain a chunk item in the chunk tree whose
corresponding block group item is absent from the extent tree; that
chunk's block group is then never inserted into the in-memory cache.
When balance iterates the chunk tree and reaches such an orphaned chunk,
should_balance_chunk() calls chunk_usage_filter(), which queries the block
group cache:
cache = btrfs_lookup_block_group(fs_info, chunk_offset);
chunk_used = cache->used; /* cache may be NULL */
btrfs_lookup_block_group() returns NULL silently when no cached entry
covers chunk_offset. chunk_usage_filter() does not check the return value,
so the immediately following dereference of cache->used triggers the crash.
[FIX]
Add a NULL check after btrfs_lookup_block_group() in chunk_usage_filter().
When the lookup fails, emit a btrfs_err() message identifying the
affected bytenr and return -EUCLEAN to indicate filesystem corruption.
Since chunk_usage_filter() now has an error path, change its return type
from bool to int: negative errno on error, 0 if the chunk passes the
usage filter, and 1 if it should be skipped. Update
should_balance_chunk() accordingly to propagate negative errors from the
usage filter path while still returning 0 for chunks that should not be
balanced and 1 for chunks that should be balanced. Finally, handle the
new negative return in __btrfs_balance() by jumping to the existing
error path, which aborts the balance operation and reports the error to
userspace.
After the fix, the same corruption is correctly detected and reported
by the filter, and the null-ptr-deref is no longer triggered.
Fixes: 5ce5b3c0916b ("Btrfs: usage filter")
Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
---
fs/btrfs/volumes.c | 32 +++++++++++++++++++++++---------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 2bec544d8ba3..1eca5fa6bdaa 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3863,14 +3863,20 @@ static bool chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 chunk_of
return ret;
}
-static bool chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
- struct btrfs_balance_args *bargs)
+static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
+ struct btrfs_balance_args *bargs)
{
struct btrfs_block_group *cache;
u64 chunk_used, user_thresh;
- bool ret = true;
+ int ret = 1;
cache = btrfs_lookup_block_group(fs_info, chunk_offset);
+ if (!cache) {
+ btrfs_err(fs_info,
+ "balance: chunk at bytenr %llu has no corresponding block group",
+ chunk_offset);
+ return -EUCLEAN;
+ }
chunk_used = cache->used;
if (bargs->usage_min == 0)
@@ -3881,7 +3887,7 @@ static bool chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
user_thresh = mult_perc(cache->length, bargs->usage);
if (chunk_used < user_thresh)
- ret = false;
+ ret = 0;
btrfs_put_block_group(cache);
return ret;
@@ -3986,8 +3992,8 @@ static bool chunk_soft_convert_filter(u64 chunk_type, struct btrfs_balance_args
return false;
}
-static bool should_balance_chunk(struct extent_buffer *leaf, struct btrfs_chunk *chunk,
- u64 chunk_offset)
+static int should_balance_chunk(struct extent_buffer *leaf, struct btrfs_chunk *chunk,
+ u64 chunk_offset)
{
struct btrfs_fs_info *fs_info = leaf->fs_info;
struct btrfs_balance_control *bctl = fs_info->balance_ctl;
@@ -4014,9 +4020,13 @@ static bool should_balance_chunk(struct extent_buffer *leaf, struct btrfs_chunk
}
/* usage filter */
- if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE) &&
- chunk_usage_filter(fs_info, chunk_offset, bargs)) {
- return false;
+ if (bargs->flags & BTRFS_BALANCE_ARGS_USAGE) {
+ int ret2 = chunk_usage_filter(fs_info, chunk_offset, bargs);
+
+ if (ret2 < 0)
+ return ret2;
+ if (ret2)
+ return false;
} else if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) &&
chunk_usage_range_filter(fs_info, chunk_offset, bargs)) {
return false;
@@ -4172,6 +4182,10 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
ret = should_balance_chunk(leaf, chunk, found_key.offset);
btrfs_release_path(path);
+ if (ret < 0) {
+ mutex_unlock(&fs_info->reclaim_bgs_lock);
+ goto error;
+ }
if (!ret) {
mutex_unlock(&fs_info->reclaim_bgs_lock);
goto loop;
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 2/4] btrfs: balance: fix null-ptr-deref in chunk_usage_range_filter
2026-03-25 0:43 [PATCH v3 0/4] btrfs: fix balance NULL derefs and chunk/bg mapping verification ZhengYuan Huang
2026-03-25 0:43 ` [PATCH v3 1/4] btrfs: balance: fix null-ptr-deref in chunk_usage_filter ZhengYuan Huang
@ 2026-03-25 0:43 ` ZhengYuan Huang
2026-03-25 0:43 ` [PATCH v3 3/4] btrfs: balance: fix null-ptr-deref in btrfs_may_alloc_data_chunk ZhengYuan Huang
2026-03-25 0:43 ` [PATCH v3 4/4] btrfs: fix check_chunk_block_group_mappings() to iterate all chunk maps ZhengYuan Huang
3 siblings, 0 replies; 5+ messages in thread
From: ZhengYuan Huang @ 2026-03-25 0:43 UTC (permalink / raw)
To: dsterba, clm, idryomov
Cc: linux-btrfs, linux-kernel, baijiaju1990, r33s3n6, zzzccc427,
ZhengYuan Huang
[BUG]
Running btrfs balance with a usage range filter (-dusage=min..max) can
trigger a null-ptr-deref when metadata corruption causes a chunk to have
no corresponding block group in the in-memory cache:
KASAN: null-ptr-deref in range [0x0000000000000070-0x0000000000000077]
RIP: 0010:chunk_usage_range_filter fs/btrfs/volumes.c:3845 [inline]
RIP: 0010:should_balance_chunk fs/btrfs/volumes.c:4031 [inline]
RIP: 0010:__btrfs_balance fs/btrfs/volumes.c:4182 [inline]
RIP: 0010:btrfs_balance+0x249e/0x4320 fs/btrfs/volumes.c:4618
...
Call Trace:
btrfs_ioctl_balance fs/btrfs/ioctl.c:3577 [inline]
btrfs_ioctl+0x25cf/0x5b90 fs/btrfs/ioctl.c:5313
vfs_ioctl fs/ioctl.c:51 [inline]
...
The bug is reproducible on next-20260312.
[CAUSE]
Two separate data structures are involved:
1. The on-disk chunk tree, which records every chunk (logical address
space region) and is iterated by __btrfs_balance().
2. The in-memory block group cache (fs_info->block_group_cache_tree),
which is built at mount time by btrfs_read_block_groups() and holds
a struct btrfs_block_group for each chunk. This cache is what the
usage range filter queries.
On a well-formed filesystem, these two are kept in 1:1 correspondence.
However, btrfs_read_block_groups() builds the cache from block group
items in the extent tree, not directly from the chunk tree. A corrupted
image can therefore contain a chunk item in the chunk tree whose
corresponding block group item is absent from the extent tree; that
chunk's block group is then never inserted into the in-memory cache.
When balance iterates the chunk tree and reaches such an orphaned chunk,
should_balance_chunk() calls chunk_usage_range_filter(), which queries
the block group cache:
cache = btrfs_lookup_block_group(fs_info, chunk_offset);
chunk_used = cache->used; /* cache may be NULL */
btrfs_lookup_block_group() returns NULL silently when no cached entry
covers chunk_offset. chunk_usage_range_filter() does not check the return
value, so the immediately following dereference of cache->used triggers
the crash.
[FIX]
Add a NULL check after btrfs_lookup_block_group() in
chunk_usage_range_filter(). When the lookup fails, emit a btrfs_err()
message identifying the affected bytenr and return -EUCLEAN to indicate
filesystem corruption.
Since chunk_usage_range_filter() now has an error path, change its
return type from bool to int: negative errno on error, 0 if the chunk
matches the usage range, and 1 if it should be filtered out. Update the
BTRFS_BALANCE_ARGS_USAGE_RANGE branch in should_balance_chunk() to
propagate negative errors from chunk_usage_range_filter() instead of
treating them as a normal filter result.
After the fix, the same corruption is correctly detected and reported
by the filter, and the null-ptr-deref is no longer triggered.
Fixes: bc3094673f22 ("btrfs: extend balance filter usage to take minimum and maximum")
Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
---
fs/btrfs/volumes.c | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 1eca5fa6bdaa..65df8652d760 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3832,16 +3832,22 @@ static bool chunk_profiles_filter(u64 chunk_type, struct btrfs_balance_args *bar
return true;
}
-static bool chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
- struct btrfs_balance_args *bargs)
+static int chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
+ struct btrfs_balance_args *bargs)
{
struct btrfs_block_group *cache;
u64 chunk_used;
u64 user_thresh_min;
u64 user_thresh_max;
- bool ret = true;
+ int ret = 1;
cache = btrfs_lookup_block_group(fs_info, chunk_offset);
+ if (!cache) {
+ btrfs_err(fs_info,
+ "balance: chunk at bytenr %llu has no corresponding block group",
+ chunk_offset);
+ return -EUCLEAN;
+ }
chunk_used = cache->used;
if (bargs->usage_min == 0)
@@ -3857,7 +3863,7 @@ static bool chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 chunk_of
user_thresh_max = mult_perc(cache->length, bargs->usage_max);
if (user_thresh_min <= chunk_used && chunk_used < user_thresh_max)
- ret = false;
+ ret = 0;
btrfs_put_block_group(cache);
return ret;
@@ -4027,9 +4033,13 @@ static int should_balance_chunk(struct extent_buffer *leaf, struct btrfs_chunk *
return ret2;
if (ret2)
return false;
- } else if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) &&
- chunk_usage_range_filter(fs_info, chunk_offset, bargs)) {
- return false;
+ } else if (bargs->flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) {
+ int ret2 = chunk_usage_range_filter(fs_info, chunk_offset, bargs);
+
+ if (ret2 < 0)
+ return ret2;
+ if (ret2)
+ return false;
}
/* devid filter */
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 3/4] btrfs: balance: fix null-ptr-deref in btrfs_may_alloc_data_chunk
2026-03-25 0:43 [PATCH v3 0/4] btrfs: fix balance NULL derefs and chunk/bg mapping verification ZhengYuan Huang
2026-03-25 0:43 ` [PATCH v3 1/4] btrfs: balance: fix null-ptr-deref in chunk_usage_filter ZhengYuan Huang
2026-03-25 0:43 ` [PATCH v3 2/4] btrfs: balance: fix null-ptr-deref in chunk_usage_range_filter ZhengYuan Huang
@ 2026-03-25 0:43 ` ZhengYuan Huang
2026-03-25 0:43 ` [PATCH v3 4/4] btrfs: fix check_chunk_block_group_mappings() to iterate all chunk maps ZhengYuan Huang
3 siblings, 0 replies; 5+ messages in thread
From: ZhengYuan Huang @ 2026-03-25 0:43 UTC (permalink / raw)
To: dsterba, clm, idryomov
Cc: linux-btrfs, linux-kernel, baijiaju1990, r33s3n6, zzzccc427,
ZhengYuan Huang
[BUG]
Running btrfs balance can trigger a null-ptr-deref before relocating a
data chunk when metadata corruption leaves a chunk in the chunk tree
without a corresponding block group in the in-memory cache:
KASAN: null-ptr-deref in range [0x0000000000000088-0x000000000000008f]
RIP: 0010:btrfs_may_alloc_data_chunk+0x40/0x1c0 fs/btrfs/volumes.c:3601
Call Trace:
__btrfs_balance fs/btrfs/volumes.c:4217 [inline]
btrfs_balance+0x2516/0x42b0 fs/btrfs/volumes.c:4604
btrfs_ioctl_balance fs/btrfs/ioctl.c:3577 [inline]
btrfs_ioctl+0x25cf/0x5b90 fs/btrfs/ioctl.c:5313
...
[CAUSE]
__btrfs_balance() iterates the on-disk chunk tree and passes the chunk
logical bytenr to btrfs_may_alloc_data_chunk() before relocating a data
chunk. That helper then queries the in-memory block group cache:
cache = btrfs_lookup_block_group(fs_info, chunk_offset);
chunk_type = cache->flags; /* cache may be NULL */
A corrupt image can contain a chunk item whose matching block group
item is missing, so no block group is ever inserted into the cache. In
that case btrfs_lookup_block_group() returns NULL.
The code only guards this with ASSERT(cache), which becomes a no-op when
CONFIG_BTRFS_ASSERT is disabled. The subsequent dereference of
cache->flags therefore crashes the kernel.
[FIX]
Add a NULL check after btrfs_lookup_block_group() in
btrfs_may_alloc_data_chunk(). If the lookup fails, emit a btrfs_err()
message identifying the affected bytenr and return -EUCLEAN to report
filesystem corruption instead of dereferencing NULL.
The caller already treats negative returns from
btrfs_may_alloc_data_chunk() as fatal errors, so balance aborts cleanly
and reports the corruption to userspace.
Fixes: a6f93c71d412 ("Btrfs: avoid losing data raid profile when deleting a device")
Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
---
fs/btrfs/volumes.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 65df8652d760..e89eb5c1dbc5 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3597,7 +3597,12 @@ static int btrfs_may_alloc_data_chunk(struct btrfs_fs_info *fs_info,
u64 chunk_type;
cache = btrfs_lookup_block_group(fs_info, chunk_offset);
- ASSERT(cache);
+ if (!cache) {
+ btrfs_err(fs_info,
+ "balance: chunk at bytenr %llu has no corresponding block group",
+ chunk_offset);
+ return -EUCLEAN;
+ }
chunk_type = cache->flags;
btrfs_put_block_group(cache);
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 4/4] btrfs: fix check_chunk_block_group_mappings() to iterate all chunk maps
2026-03-25 0:43 [PATCH v3 0/4] btrfs: fix balance NULL derefs and chunk/bg mapping verification ZhengYuan Huang
` (2 preceding siblings ...)
2026-03-25 0:43 ` [PATCH v3 3/4] btrfs: balance: fix null-ptr-deref in btrfs_may_alloc_data_chunk ZhengYuan Huang
@ 2026-03-25 0:43 ` ZhengYuan Huang
3 siblings, 0 replies; 5+ messages in thread
From: ZhengYuan Huang @ 2026-03-25 0:43 UTC (permalink / raw)
To: dsterba, clm, idryomov
Cc: linux-btrfs, linux-kernel, baijiaju1990, r33s3n6, zzzccc427,
ZhengYuan Huang
[BUG]
A corrupted image with a chunk present in the chunk tree but whose
corresponding block group item is missing from the extent tree can be
mounted successfully, even though check_chunk_block_group_mappings()
is supposed to catch exactly this corruption at mount time. Once
mounted, running btrfs balance with a usage filter (-dusage=N or
-dusage=min..max) triggers a null-ptr-deref:
KASAN: null-ptr-deref in range [0x0000000000000070-0x0000000000000077]
RIP: 0010:chunk_usage_filter fs/btrfs/volumes.c:3874 [inline]
RIP: 0010:should_balance_chunk fs/btrfs/volumes.c:4018 [inline]
RIP: 0010:__btrfs_balance fs/btrfs/volumes.c:4172 [inline]
RIP: 0010:btrfs_balance+0x2024/0x42b0 fs/btrfs/volumes.c:4604
[CAUSE]
The crash occurs because __btrfs_balance() iterates the on-disk chunk
tree, finds the orphaned chunk, calls chunk_usage_filter() (or
chunk_usage_range_filter()), which queries the in-memory block group
cache via btrfs_lookup_block_group(). Since no block group was ever
inserted for this chunk, the lookup returns NULL, and the subsequent
dereference of cache->used crashes.
check_chunk_block_group_mappings() uses btrfs_find_chunk_map() to
iterate the in-memory chunk map (fs_info->mapping_tree):
map = btrfs_find_chunk_map(fs_info, start, 1);
With @start = 0 and @length = 1, btrfs_find_chunk_map() looks for a
chunk map that *contains* the logical address 0. If no chunk contains
logical address 0, btrfs_find_chunk_map(fs_info, 0, 1) returns NULL
immediately and the loop breaks after the very first iteration,
having checked zero chunks. The entire verification function is therefore
a no-op, and the corrupted image passes the mount-time check undetected.
[FIX]
Replace the btrfs_find_chunk_map() based loop with a direct in-order
walk of fs_info->mapping_tree using rb_first_cached() + rb_next().
This guarantees that every chunk map in the tree is visited regardless
of the logical addresses involved.
No lock is taken around the traversal. This function is called during
mount from btrfs_read_block_groups(), which is invoked from open_ctree()
before any background threads (cleaner, transaction kthread, etc.) are
started. There are therefore no concurrent writers that could modify
mapping_tree at this point. An analogous lockless direct traversal of
mapping_tree already exists in fill_dummy_bgs() in the same file.
Since we walk the RB-tree directly via rb_entry() without going through
btrfs_find_chunk_map(), no reference is taken on each map entry, so the
btrfs_free_chunk_map() calls are also removed.
Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
---
fs/btrfs/block-group.c | 24 +++++++++---------------
1 file changed, 9 insertions(+), 15 deletions(-)
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index 5322ef2ae015..d1e075a8905a 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -2319,29 +2319,26 @@ static struct btrfs_block_group *btrfs_create_block_group_cache(
*/
static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info)
{
- u64 start = 0;
+ struct rb_node *node;
int ret = 0;
- while (1) {
+ /*
+ * This is called during mount from btrfs_read_block_groups(), before
+ * any background threads are started, so no concurrent writers can
+ * modify the mapping_tree. No lock is needed here.
+ */
+ for (node = rb_first_cached(&fs_info->mapping_tree); node;
+ node = rb_next(node)) {
struct btrfs_chunk_map *map;
struct btrfs_block_group *bg;
- /*
- * btrfs_find_chunk_map() will return the first chunk map
- * intersecting the range, so setting @length to 1 is enough to
- * get the first chunk.
- */
- map = btrfs_find_chunk_map(fs_info, start, 1);
- if (!map)
- break;
-
+ map = rb_entry(node, struct btrfs_chunk_map, rb_node);
bg = btrfs_lookup_block_group(fs_info, map->start);
if (unlikely(!bg)) {
btrfs_err(fs_info,
"chunk start=%llu len=%llu doesn't have corresponding block group",
map->start, map->chunk_len);
ret = -EUCLEAN;
- btrfs_free_chunk_map(map);
break;
}
if (unlikely(bg->start != map->start || bg->length != map->chunk_len ||
@@ -2354,12 +2351,9 @@ static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info)
bg->start, bg->length,
bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK);
ret = -EUCLEAN;
- btrfs_free_chunk_map(map);
btrfs_put_block_group(bg);
break;
}
- start = map->start + map->chunk_len;
- btrfs_free_chunk_map(map);
btrfs_put_block_group(bg);
}
return ret;
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-03-25 0:44 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-25 0:43 [PATCH v3 0/4] btrfs: fix balance NULL derefs and chunk/bg mapping verification ZhengYuan Huang
2026-03-25 0:43 ` [PATCH v3 1/4] btrfs: balance: fix null-ptr-deref in chunk_usage_filter ZhengYuan Huang
2026-03-25 0:43 ` [PATCH v3 2/4] btrfs: balance: fix null-ptr-deref in chunk_usage_range_filter ZhengYuan Huang
2026-03-25 0:43 ` [PATCH v3 3/4] btrfs: balance: fix null-ptr-deref in btrfs_may_alloc_data_chunk ZhengYuan Huang
2026-03-25 0:43 ` [PATCH v3 4/4] btrfs: fix check_chunk_block_group_mappings() to iterate all chunk maps ZhengYuan Huang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox