When running generic/475, we may get the following warning in dmesg:
[ 6902.102154] WARNING: CPU: 3 PID: 18013 at fs/btrfs/extent-tree.c:9776 btrfs_free_block_groups+0x2af/0x3b0 [btrfs]
[ 6902.109160] CPU: 3 PID: 18013 Comm: umount Tainted: G W O 4.19.0-rc8+ #8
[ 6902.110971] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
[ 6902.112857] RIP: 0010:btrfs_free_block_groups+0x2af/0x3b0 [btrfs]
[ 6902.118921] RSP: 0018:
ffffc9000459bdb0 EFLAGS:
00010286
[ 6902.120315] RAX:
ffff880175050bb0 RBX:
ffff8801124a8000 RCX:
0000000000170007
[ 6902.121969] RDX:
0000000000000002 RSI:
0000000000170007 RDI:
ffffffff8125fb74
[ 6902.123716] RBP:
ffff880175055d10 R08:
0000000000000000 R09:
0000000000000000
[ 6902.125417] R10:
0000000000000000 R11:
0000000000000000 R12:
ffff880175055d88
[ 6902.127129] R13:
ffff880175050bb0 R14:
0000000000000000 R15:
dead000000000100
[ 6902.129060] FS:
00007f4507223780(0000) GS:
ffff88017ba00000(0000) knlGS:
0000000000000000
[ 6902.130996] CS: 0010 DS: 0000 ES: 0000 CR0:
0000000080050033
[ 6902.132558] CR2:
00005623599cac78 CR3:
000000014b700001 CR4:
00000000003606e0
[ 6902.134270] DR0:
0000000000000000 DR1:
0000000000000000 DR2:
0000000000000000
[ 6902.135981] DR3:
0000000000000000 DR6:
00000000fffe0ff0 DR7:
0000000000000400
[ 6902.137836] Call Trace:
[ 6902.138939] close_ctree+0x171/0x330 [btrfs]
[ 6902.140181] ? kthread_stop+0x146/0x1f0
[ 6902.141277] generic_shutdown_super+0x6c/0x100
[ 6902.142517] kill_anon_super+0x14/0x30
[ 6902.143554] btrfs_kill_super+0x13/0x100 [btrfs]
[ 6902.144790] deactivate_locked_super+0x2f/0x70
[ 6902.146014] cleanup_mnt+0x3b/0x70
[ 6902.147020] task_work_run+0x9e/0xd0
[ 6902.148036] do_syscall_64+0x470/0x600
[ 6902.149142] ? trace_hardirqs_off_thunk+0x1a/0x1c
[ 6902.150375] entry_SYSCALL_64_after_hwframe+0x49/0xbe
[ 6902.151640] RIP: 0033:0x7f45077a6a7b
[ 6902.157324] RSP: 002b:
00007ffd589f3e68 EFLAGS:
00000246 ORIG_RAX:
00000000000000a6
[ 6902.159187] RAX:
0000000000000000 RBX:
000055e8eec732b0 RCX:
00007f45077a6a7b
[ 6902.160834] RDX:
0000000000000001 RSI:
0000000000000000 RDI:
000055e8eec73490
[ 6902.162526] RBP:
0000000000000000 R08:
000055e8eec734b0 R09:
00007ffd589f26c0
[ 6902.164141] R10:
0000000000000000 R11:
0000000000000246 R12:
000055e8eec73490
[ 6902.165815] R13:
00007f4507ac61a4 R14:
0000000000000000 R15:
00007ffd589f40d8
[ 6902.167553] irq event stamp: 0
[ 6902.168998] hardirqs last enabled at (0): [<
0000000000000000>] (null)
[ 6902.170731] hardirqs last disabled at (0): [<
ffffffff810cd810>] copy_process.part.55+0x3b0/0x1f00
[ 6902.172773] softirqs last enabled at (0): [<
ffffffff810cd810>] copy_process.part.55+0x3b0/0x1f00
[ 6902.174671] softirqs last disabled at (0): [<
0000000000000000>] (null)
[ 6902.176407] ---[ end trace
463138c2986b275c ]---
[ 6902.177636] BTRFS info (device dm-3): space_info 4 has
273465344 free, is not full
[ 6902.179453] BTRFS info (device dm-3): space_info total=
276824064, used=4685824, pinned=
18446744073708158976, reserved=0, may_use=0, readonly=65536
In the above line there's "pinned=
18446744073708158976" which is an
unsigned u64 value of -1392640, an obvious underflow.
When transaction_kthread is running cleanup_transaction(), another
fsstress is running btrfs_commit_transaction(). The
btrfs_finish_extent_commit() may get the same range as
btrfs_destroy_pinned_extent() got, which causes the pinned underflow.
Fixes:
d4b450cd4b33 ("Btrfs: fix race between transaction commit and empty block group removal")
CC: stable@vger.kernel.org # 4.4+
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
unpin = pinned_extents;
again:
while (1) {
+ /*
+ * The btrfs_finish_extent_commit() may get the same range as
+ * ours between find_first_extent_bit and clear_extent_dirty.
+ * Hence, hold the unused_bg_unpin_mutex to avoid double unpin
+ * the same extent range.
+ */
+ mutex_lock(&fs_info->unused_bg_unpin_mutex);
ret = find_first_extent_bit(unpin, 0, &start, &end,
EXTENT_DIRTY, NULL);
- if (ret)
+ if (ret) {
+ mutex_unlock(&fs_info->unused_bg_unpin_mutex);
break;
+ }
clear_extent_dirty(unpin, start, end);
btrfs_error_unpin_extent_range(fs_info, start, end);
+ mutex_unlock(&fs_info->unused_bg_unpin_mutex);
cond_resched();
}