Skip to content

Commit ea57788

Browse files
adam900710kdave
authored andcommitted
btrfs: require only sector size alignment for parent eb bytenr
[BUG] A completely sane converted fs will cause kernel warning at balance time: [ 1557.188633] BTRFS info (device sda7): relocating block group 8162107392 flags data [ 1563.358078] BTRFS info (device sda7): found 11722 extents [ 1563.358277] BTRFS info (device sda7): leaf 7989321728 gen 95 total ptrs 213 free space 3458 owner 2 [ 1563.358280] item 0 key (7984947200 169 0) itemoff 16250 itemsize 33 [ 1563.358281] extent refs 1 gen 90 flags 2 [ 1563.358282] ref#0: tree block backref root 4 [ 1563.358285] item 1 key (7985602560 169 0) itemoff 16217 itemsize 33 [ 1563.358286] extent refs 1 gen 93 flags 258 [ 1563.358287] ref#0: shared block backref parent 7985602560 [ 1563.358288] (parent 7985602560 is NOT ALIGNED to nodesize 16384) [ 1563.358290] item 2 key (7985635328 169 0) itemoff 16184 itemsize 33 ... [ 1563.358995] BTRFS error (device sda7): eb 7989321728 invalid extent inline ref type 182 [ 1563.358996] ------------[ cut here ]------------ [ 1563.359005] WARNING: CPU: 14 PID: 2930 at 0xffffffff9f231766 Then with transaction abort, and obviously failed to balance the fs. [CAUSE] That mentioned inline ref type 182 is completely sane, it's BTRFS_SHARED_BLOCK_REF_KEY, it's some extra check making kernel to believe it's invalid. Commit 64ecdb6 ("Btrfs: add one more sanity check for shared ref type") introduced extra checks for backref type. One of the requirement is, parent bytenr must be aligned to node size, which is not correct. One example is like this: 0 1G 1G+4K 2G 2G+4K | |///////////////////|//| <- A chunk starts at 1G+4K | | <- A tree block get reserved at bytenr 1G+4K Then we have a valid tree block at bytenr 1G+4K, but not aligned to nodesize (16K). Such chunk is not ideal, but current kernel can handle it pretty well. We may warn about such tree block in the future, but should not reject them. [FIX] Change the alignment requirement from node size alignment to sector size alignment. Also, to make our lives a little easier, also output @iref when btrfs_get_extent_inline_ref_type() failed, so we can locate the item easier. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=205475 Fixes: 64ecdb6 ("Btrfs: add one more sanity check for shared ref type") CC: [email protected] # 4.14+ Reviewed-by: Josef Bacik <[email protected]> Signed-off-by: Qu Wenruo <[email protected]> [ update comments and messages ] Signed-off-by: David Sterba <[email protected]>
1 parent fccc000 commit ea57788

File tree

2 files changed

+16
-15
lines changed

2 files changed

+16
-15
lines changed

fs/btrfs/extent-tree.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -400,12 +400,11 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
400400
if (type == BTRFS_SHARED_BLOCK_REF_KEY) {
401401
ASSERT(eb->fs_info);
402402
/*
403-
* Every shared one has parent tree
404-
* block, which must be aligned to
405-
* nodesize.
403+
* Every shared one has parent tree block,
404+
* which must be aligned to sector size.
406405
*/
407406
if (offset &&
408-
IS_ALIGNED(offset, eb->fs_info->nodesize))
407+
IS_ALIGNED(offset, eb->fs_info->sectorsize))
409408
return type;
410409
}
411410
} else if (is_data == BTRFS_REF_TYPE_DATA) {
@@ -414,12 +413,11 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
414413
if (type == BTRFS_SHARED_DATA_REF_KEY) {
415414
ASSERT(eb->fs_info);
416415
/*
417-
* Every shared one has parent tree
418-
* block, which must be aligned to
419-
* nodesize.
416+
* Every shared one has parent tree block,
417+
* which must be aligned to sector size.
420418
*/
421419
if (offset &&
422-
IS_ALIGNED(offset, eb->fs_info->nodesize))
420+
IS_ALIGNED(offset, eb->fs_info->sectorsize))
423421
return type;
424422
}
425423
} else {
@@ -429,8 +427,9 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
429427
}
430428

431429
btrfs_print_leaf((struct extent_buffer *)eb);
432-
btrfs_err(eb->fs_info, "eb %llu invalid extent inline ref type %d",
433-
eb->start, type);
430+
btrfs_err(eb->fs_info,
431+
"eb %llu iref 0x%lx invalid extent inline ref type %d",
432+
eb->start, (unsigned long)iref, type);
434433
WARN_ON(1);
435434

436435
return BTRFS_REF_TYPE_INVALID;

fs/btrfs/print-tree.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,10 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
9595
* offset is supposed to be a tree block which
9696
* must be aligned to nodesize.
9797
*/
98-
if (!IS_ALIGNED(offset, eb->fs_info->nodesize))
99-
pr_info("\t\t\t(parent %llu is NOT ALIGNED to nodesize %llu)\n",
100-
offset, (unsigned long long)eb->fs_info->nodesize);
98+
if (!IS_ALIGNED(offset, eb->fs_info->sectorsize))
99+
pr_info(
100+
"\t\t\t(parent %llu not aligned to sectorsize %u)\n",
101+
offset, eb->fs_info->sectorsize);
101102
break;
102103
case BTRFS_EXTENT_DATA_REF_KEY:
103104
dref = (struct btrfs_extent_data_ref *)(&iref->offset);
@@ -112,8 +113,9 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
112113
* must be aligned to nodesize.
113114
*/
114115
if (!IS_ALIGNED(offset, eb->fs_info->nodesize))
115-
pr_info("\t\t\t(parent %llu is NOT ALIGNED to nodesize %llu)\n",
116-
offset, (unsigned long long)eb->fs_info->nodesize);
116+
pr_info(
117+
"\t\t\t(parent %llu not aligned to sectorsize %u)\n",
118+
offset, eb->fs_info->sectorsize);
117119
break;
118120
default:
119121
pr_cont("(extent %llu has INVALID ref type %d)\n",

0 commit comments

Comments
 (0)