Skip to content

Commit 938fcbf

Browse files
josefbacikkdave
authored andcommitted
btrfs: splice remaining dirty_bg's onto the transaction dirty bg list
While doing error injection testing with my relocation patches I hit the following assert: assertion failed: list_empty(&block_group->dirty_list), in fs/btrfs/block-group.c:3356 ------------[ cut here ]------------ kernel BUG at fs/btrfs/ctree.h:3357! invalid opcode: 0000 [#1] SMP NOPTI CPU: 0 PID: 24351 Comm: umount Tainted: G W 5.10.0-rc3+ #193 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-2.fc32 04/01/2014 RIP: 0010:assertfail.constprop.0+0x18/0x1a RSP: 0018:ffffa09b019c7e00 EFLAGS: 00010282 RAX: 0000000000000056 RBX: ffff8f6492c18000 RCX: 0000000000000000 RDX: ffff8f64fbc27c60 RSI: ffff8f64fbc19050 RDI: ffff8f64fbc19050 RBP: ffff8f6483bbdc00 R08: 0000000000000000 R09: 0000000000000000 R10: ffffa09b019c7c38 R11: ffffffff85d70928 R12: ffff8f6492c18100 R13: ffff8f6492c18148 R14: ffff8f6483bbdd70 R15: dead000000000100 FS: 00007fbfda4cdc40(0000) GS:ffff8f64fbc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fbfda666fd0 CR3: 000000013cf66002 CR4: 0000000000370ef0 Call Trace: btrfs_free_block_groups.cold+0x55/0x55 close_ctree+0x2c5/0x306 ? fsnotify_destroy_marks+0x14/0x100 generic_shutdown_super+0x6c/0x100 kill_anon_super+0x14/0x30 btrfs_kill_super+0x12/0x20 deactivate_locked_super+0x36/0xa0 cleanup_mnt+0x12d/0x190 task_work_run+0x5c/0xa0 exit_to_user_mode_prepare+0x1b1/0x1d0 syscall_exit_to_user_mode+0x54/0x280 entry_SYSCALL_64_after_hwframe+0x44/0xa9 This happened because I injected an error in btrfs_cow_block() while running the dirty block groups. When we run the dirty block groups, we splice the list onto a local list to process. However if an error occurs, we only cleanup the transactions dirty block group list, not any pending block groups we have on our locally spliced list. In fact if we fail to allocate a path in this function we'll also fail to clean up the splice list. Fix this by splicing the list back onto the transaction dirty block group list so that the block groups are cleaned up. Then add a 'out' label and have the error conditions jump to out so that the errors are handled properly. This also has the side-effect of fixing a problem where we would clear 'ret' on error because we unconditionally ran btrfs_run_delayed_refs(). CC: [email protected] # 4.4+ Signed-off-by: Josef Bacik <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent c78a10a commit 938fcbf

File tree

1 file changed

+12
-7
lines changed

1 file changed

+12
-7
lines changed

fs/btrfs/block-group.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2564,8 +2564,10 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans)
25642564

25652565
if (!path) {
25662566
path = btrfs_alloc_path();
2567-
if (!path)
2568-
return -ENOMEM;
2567+
if (!path) {
2568+
ret = -ENOMEM;
2569+
goto out;
2570+
}
25692571
}
25702572

25712573
/*
@@ -2659,16 +2661,14 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans)
26592661
btrfs_put_block_group(cache);
26602662
if (drop_reserve)
26612663
btrfs_delayed_refs_rsv_release(fs_info, 1);
2662-
2663-
if (ret)
2664-
break;
2665-
26662664
/*
26672665
* Avoid blocking other tasks for too long. It might even save
26682666
* us from writing caches for block groups that are going to be
26692667
* removed.
26702668
*/
26712669
mutex_unlock(&trans->transaction->cache_write_mutex);
2670+
if (ret)
2671+
goto out;
26722672
mutex_lock(&trans->transaction->cache_write_mutex);
26732673
}
26742674
mutex_unlock(&trans->transaction->cache_write_mutex);
@@ -2692,7 +2692,12 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans)
26922692
goto again;
26932693
}
26942694
spin_unlock(&cur_trans->dirty_bgs_lock);
2695-
} else if (ret < 0) {
2695+
}
2696+
out:
2697+
if (ret < 0) {
2698+
spin_lock(&cur_trans->dirty_bgs_lock);
2699+
list_splice_init(&dirty, &cur_trans->dirty_bgs);
2700+
spin_unlock(&cur_trans->dirty_bgs_lock);
26962701
btrfs_cleanup_dirty_bgs(cur_trans, fs_info);
26972702
}
26982703

0 commit comments

Comments
 (0)