summaryrefslogtreecommitdiff
path: root/extent-tree.c
diff options
context:
space:
mode:
authorQu Wenruo <quwenruo@cn.fujitsu.com>2016-10-24 15:22:33 +0800
committerDavid Sterba <dsterba@suse.com>2016-10-25 14:31:06 +0200
commitffb1b847bd554e45c00212280847b9f2059a87f3 (patch)
treeac814579158f3a29451ed842850989ca7c000d8e /extent-tree.c
parentb2fbfc8cdd4ce4bf7d22e55695a4cc7e707c9ef3 (diff)
btrfs-progs: Fix wrong tree block alignment for unalianged block group
Commit 854437ca(btrfs-progs: extent-tree: avoid allocating tree block that crosses stripe boundary) introduces check for logical bytenr not crossing stripe boundary. However that check is not completely correct. It only checks if the logical bytenr and length agaist absolute logical offset. That's to say, it only check if a tree block lies in 64K logical stripe. But in fact, it's possible a block group starts at bytenr unaligned with 64K, just like the following case. Then btrfsck will give false alert. 0 32K 64K 96K 128K 160K ... |--------------- Block group A --------------------- |<-----TB 32K------>| |/Scrub stripe unit/| | WRONG UNIT | In that case, TB(tree block) at bytenr 32K in fact fits into the kernel scrub stripe unit. But doesn't fit into the pure logical 64K stripe. Fix check_crossing_stripes() to compare bytenr to block group start, not to absolute logical bytenr. Reported-by: Jussi Kansanen <jussi.kansanen@gmail.com> Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'extent-tree.c')
-rw-r--r--extent-tree.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/extent-tree.c b/extent-tree.c
index f6d0a7c1..3b1577e7 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -2606,11 +2606,20 @@ check_failed:
}
if (!(data & BTRFS_BLOCK_GROUP_DATA)) {
- if (check_crossing_stripes(ins->objectid, num_bytes)) {
- search_start = round_down(ins->objectid + num_bytes,
- BTRFS_STRIPE_LEN);
+ if (check_crossing_stripes(info, ins->objectid, num_bytes)) {
+ struct btrfs_block_group_cache *bg_cache;
+ u64 bg_offset;
+
+ bg_cache = btrfs_lookup_block_group(info, ins->objectid);
+ if (!bg_cache)
+ goto no_bg_cache;
+ bg_offset = ins->objectid - bg_cache->key.objectid;
+
+ search_start = round_up(bg_offset + num_bytes,
+ BTRFS_STRIPE_LEN) + bg_offset;
goto new_group;
}
+no_bg_cache:
block_group = btrfs_lookup_block_group(info, ins->objectid);
if (block_group)
trans->block_group = block_group;