btrfs: extent-tree: kill the BUG_ON() in insert_inline_extent_backref()

[BUG]
With a crafted image, btrfs can panic at insert_inline_extent_backref():

  kernel BUG at fs/btrfs/extent-tree.c:1857!
  invalid opcode: 0000 [#1] SMP PTI
  CPU: 0 PID: 1117 Comm: btrfs-transacti Not tainted 5.0.0-rc8+ #9
  RIP: 0010:insert_inline_extent_backref+0xcc/0xe0
  RSP: 0018:ffffac4dc1287be8 EFLAGS: 00010293
  RAX: 0000000000000000 RBX: 0000000000000007 RCX: 0000000000000001
  RDX: 0000000000001000 RSI: 0000000000000000 RDI: 0000000000000000
  RBP: ffffac4dc1287c28 R08: ffffac4dc1287ab8 R09: ffffac4dc1287ac0
  R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000
  R13: ffff8febef88a540 R14: ffff8febeaa7bc30 R15: 0000000000000000
  FS: 0000000000000000(0000) GS:ffff8febf7a00000(0000) knlGS:0000000000000000
  CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  CR2: 00007f663ace94c0 CR3: 0000000235698006 CR4: 00000000000206f0
  Call Trace:
  ? _cond_resched+0x1a/0x50
  __btrfs_inc_extent_ref.isra.64+0x7e/0x240
  ? btrfs_merge_delayed_refs+0xa5/0x330
  __btrfs_run_delayed_refs+0x653/0x1120
  btrfs_run_delayed_refs+0xdb/0x1b0
  btrfs_commit_transaction+0x52/0x950
  ? start_transaction+0x94/0x450
  transaction_kthread+0x163/0x190
  kthread+0x105/0x140
  ? btrfs_cleanup_transaction+0x560/0x560
  ? kthread_destroy_worker+0x50/0x50
  ret_from_fork+0x35/0x40
  Modules linked in:
  ---[ end trace 2ad8b3de903cf825 ]---

[CAUSE]
Due to extent tree corruption (still valid by itself, but bad cross
ref), we can allocate an extent which is still in extent tree.  The
offending tree block of that case is from csum tree.  The newly
allocated tree block is also for csum tree.

Then we will try to insert a tree block ref for the existing tree block
ref.

For a tree extent item, tree block can never be shared directly by the
same tree twice.  We have such BUG_ON() to prevent such problem, but
this is not a proper error handling.

[FIX]
Replace that BUG_ON() with proper error message and leaf dump for debug
build.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=202829
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2020-08-19 14:35:49 +08:00 committed by David Sterba
parent 1c2a07f598
commit 07cce5cf3b
1 changed files with 19 additions and 1 deletions

View File

@ -1177,7 +1177,22 @@ int insert_inline_extent_backref(struct btrfs_trans_handle *trans,
num_bytes, parent, root_objectid, num_bytes, parent, root_objectid,
owner, offset, 1); owner, offset, 1);
if (ret == 0) { if (ret == 0) {
BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID); /*
* We're adding refs to a tree block we already own, this
* should not happen at all.
*/
if (owner < BTRFS_FIRST_FREE_OBJECTID) {
btrfs_crit(trans->fs_info,
"adding refs to an existing tree ref, bytenr %llu num_bytes %llu root_objectid %llu",
bytenr, num_bytes, root_objectid);
if (IS_ENABLED(CONFIG_BTRFS_DEBUG)) {
WARN_ON(1);
btrfs_crit(trans->fs_info,
"path->slots[0]=%d path->nodes[0]:", path->slots[0]);
btrfs_print_leaf(path->nodes[0]);
}
return -EUCLEAN;
}
update_inline_extent_backref(path, iref, refs_to_add, update_inline_extent_backref(path, iref, refs_to_add,
extent_op, NULL); extent_op, NULL);
} else if (ret == -ENOENT) { } else if (ret == -ENOENT) {
@ -1397,6 +1412,9 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
/* /*
* __btrfs_inc_extent_ref - insert backreference for a given extent * __btrfs_inc_extent_ref - insert backreference for a given extent
* *
* The counterpart is in __btrfs_free_extent(), with examples and more details
* how it works.
*
* @trans: Handle of transaction * @trans: Handle of transaction
* *
* @node: The delayed ref node used to get the bytenr/length for * @node: The delayed ref node used to get the bytenr/length for