Btrfs: fix ASSERT(list_empty(&cur_trans->dirty_bgs_list)
PATCH 1/1 Btrfs: fix ASSERT(list_empty(&cur_trans->dirty_bgs_list)
Dave could hit this assert consistently running btrfs/078. This is because when we update the block groups we could truncate the free space, which would try to delete the csums for that range and dirty the csum root. For this to happen we have to have already written out the csum root so it's kind of hard to hit this case. This patch fixes this by changing the logic to only write the dirty block groups if the dirty_cowonly_roots list is empty. This will get us the same effect as before since we add the extent root last, and will cover the case that we dirty some other root again but not the extent root. Thanks,
--- fs/btrfs/transaction.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
fs/btrfs/transaction.c +9 -3
@@ -1023,16 +1023,22 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,u64 old_root_bytenr;u64 old_root_used;struct btrfs_root *tree_root = root->fs_info->tree_root; -bool extent_root = (root->objectid ==BTRFS_EXTENT_TREE_OBJECTID ); +struct btrfs_fs_info *fs_info = root->fs_info; old_root_used =btrfs_root_used (&root->root_item);btrfs_write_dirty_block_groups (trans, root);while (1 ) { old_root_bytenr =btrfs_root_bytenr (&root->root_item); + +/* +* We can only break out if our root matches the root item and +* we either have more roots to process or we have no more roots +* to process and there are no empty bgs. +*/ if (old_root_bytenr == root->node->start && old_root_used ==btrfs_root_used (&root->root_item) && - (!extent_root || + (!list_empty (&fs_info->dirty_cowonly_roots) ||list_empty (&trans->transaction->dirty_bgs)))break ;
@@ -1044,7 +1050,7 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,return ret; old_root_used =btrfs_root_used (&root->root_item); -if (extent_root) { +if (list_empty (&fs_info->dirty_cowonly_roots)) { ret =btrfs_write_dirty_block_groups (trans, root);if (ret)return ret;
Signature · 1 line
1.8.3.1
Quoted 8 lines · Josef Bacik
Dave could hit this assert consistently running btrfs/078. This is because when we update the block groups we could truncate the free space, which would try to delete the csums for that range and dirty the csum root. For this to happen we have to have already written out the csum root so it's kind of hard to hit this case. This patch fixes this by changing the logic to only write the dirty block groups if the
dirty_cowonly_rootslist is empty. This will get us the same effect as before since we add the extent root last, and will cover the case that we dirty some other root again but not the extent root. Thanks,
Free space inode is NODATASUM, so its searching csum tree in __btrfs_free_extent() is really unnecessary, by skipping that, csum tree won't be inserted into dirty_cowonly_roots list again, so it also passed btrfs/078, at least on my box.
Thanks,
-liubo
Quoted 52 lines
Reported-by David Sterba <[email protected]>Signed-off-by Josef Bacik <[email protected]>--- fs/btrfs/transaction.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)fs/btrfs/transaction.c +9
-3@@ -1023,16 +1023,22 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,u64 old_root_bytenr;u64 old_root_used;struct btrfs_root *tree_root = root->fs_info->tree_root; -bool extent_root = (root->objectid ==BTRFS_EXTENT_TREE_OBJECTID ); +struct btrfs_fs_info *fs_info = root->fs_info; old_root_used =btrfs_root_used (&root->root_item);btrfs_write_dirty_block_groups (trans, root);while (1 ) { old_root_bytenr =btrfs_root_bytenr (&root->root_item); + +/* +* We can only break out if our root matches the root item and +* we either have more roots to process or we have no more roots +* to process and there are no empty bgs. +*/ if (old_root_bytenr == root->node->start && old_root_used ==btrfs_root_used (&root->root_item) && - (!extent_root || + (!list_empty (&fs_info->dirty_cowonly_roots) ||list_empty (&trans->transaction->dirty_bgs)))break ;@@ -1044,7 +1050,7 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,return ret; old_root_used =btrfs_root_used (&root->root_item); -if (extent_root) { +if (list_empty (&fs_info->dirty_cowonly_roots)) { ret =btrfs_write_dirty_block_groups (trans, root);if (ret)return ret;Signature · 6 lines
1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 10 lines · Liu Bo
Quoted 8 lines · Josef Bacik
Dave could hit this assert consistently running btrfs/078. This is because when we update the block groups we could truncate the free space, which would try to delete the csums for that range and dirty the csum root. For this to happen we have to have already written out the csum root so it's kind of hard to hit this case. This patch fixes this by changing the logic to only write the dirty block groups if the
dirty_cowonly_rootslist is empty. This will get us the same effect as before since we add the extent root last, and will cover the case that we dirty some other root again but not the extent root. Thanks,
Quoted 4 lines
Free space inode is NODATASUM, so its searching csum tree in
__btrfs_free_extent()is really unnecessary, by skipping that, csum tree won't be inserted intodirty_cowonly_rootslist again, so it also passed btrfs/078, at least on my box.
I can hit the bug [1] even with Josef's patch, I'm can test your fix if you want.
MKFS_OPTIONS -- -O skinny-metadata,extref -m single -d single --mixed /dev/sdc1 MOUNT_OPTIONS -- -o enospc_debug,space_cache,noatime /dev/sdc1 /mnt/a2
on top of 3.19-rc5 with Chris' for-linus.
[1]
[ 773.601170] BTRFS: assertion failed: list_empty(&cur_trans->dirty_bgs), file: fs/btrfs/transaction.c, line: 2007 [ 773.601170] ------------[ cut here ]------------ [ 773.601172] kernel BUG at fs/btrfs/ctree.h:4012! [ 773.601177] invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC [ 773.601183] Modules linked in: rpcsec_gss_krb5 loop btrfs [ 773.601187] CPU: 1 PID: 28350 Comm: fsstress Tainted: G W 3.19.0-rc5-default+ #233 [ 773.601189] Hardware name: Intel Corporation Santa Rosa platform/Matanzas, BIOS TSRSCRB1.86C.0047.B00.0610170821 10/17/06 [ 773.601191] task: ffff88004e220000 ti: ffff880076f30000 task.ti: ffff880076f30000 [ 773.601220] RIP: 0010:[<ffffffffa003824e>] [<ffffffffa003824e>] assfail.clone.0+0x1e/0x20 [btrfs] [ 773.601224] RSP: 0018:ffff880076f33e58 EFLAGS: 00010292 [ 773.601226] RAX: 0000000000000064 RBX: ffff8800789026e0 RCX: 0000000000000001 [ 773.601227] RDX: 0000000000000001 RSI: 0000000000000001 RDI: 0000000000000001 [ 773.601229] RBP: ffff880076f33e58 R08: 0000000000000001 R09: 0000000000000000 [ 773.601230] R10: 0000000000000001 R11: 0000000000000001 R12: ffff880075c3d000 [ 773.601232] R13: ffff880078927518 R14: ffff880078927380 R15: ffff88006bab63a8 [ 773.601234] FS: 00007fb829fd4700(0000) GS:ffff88007d400000(0000) knlGS:0000000000000000 [ 773.601236] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 773.601237] CR2: 00007f0fa86f3990 CR3: 0000000079102000 CR4: 00000000000007e0 [ 773.601239] Stack: [ 773.601244] ffff880076f33ed8 ffffffffa0039d9b ffff88007892738c 00ff880075c3d000 [ 773.601249] 0000000000000000 ffff88004e220000 ffff8800781dd730 ffff880075c3d000 [ 773.601254] ffff880075c3d000 ffff880075f7e868 0000000000000001 ffff8800781dc000 [ 773.601256] Call Trace: [ 773.601274] [<ffffffffa0039d9b>] btrfs_commit_transaction+0xb1b/0xb60 [btrfs] [ 773.601289] [<ffffffffa0004679>] btrfs_sync_fs+0x79/0x120 [btrfs] [ 773.601295] [<ffffffff811d3610>] ? SyS_tee+0x360/0x360 [ 773.601298] [<ffffffff811d3630>] sync_fs_one_sb+0x20/0x30 [ 773.601303] [<ffffffff811a5231>] iterate_supers+0xf1/0x100 [ 773.601307] [<ffffffff811d3965>] sys_sync+0x55/0x90 [ 773.601313] [<ffffffff81a9fc12>] system_call_fastpath+0x12/0x17
Quoted 16 lines · David Sterba
Quoted 10 lines · Liu Bo
Quoted 8 lines · Josef Bacik
Dave could hit this assert consistently running btrfs/078. This is because when we update the block groups we could truncate the free space, which would try to delete the csums for that range and dirty the csum root. For this to happen we have to have already written out the csum root so it's kind of hard to hit this case. This patch fixes this by changing the logic to only write the dirty block groups if the
dirty_cowonly_rootslist is empty. This will get us the same effect as before since we add the extent root last, and will cover the case that we dirty some other root again but not the extent root. Thanks,Quoted 4 lines
Free space inode is NODATASUM, so its searching csum tree in
__btrfs_free_extent()is really unnecessary, by skipping that, csum tree won't be inserted intodirty_cowonly_rootslist again, so it also passed btrfs/078, at least on my box.
Quoted 7 lines
I can hit the bug [1] even with Josef's patch, I'm can test your fix if you want.
MKFS_OPTIONS-- -O skinny-metadata,extref -m single -d single --mixed/dev/sdc1MOUNT_OPTIONS-- -o enospc_debug,space_cache,noatime/dev/sdc1/mnt/a2on top of 3.19-rc5 with Chris' for-linus.
I tested this fix on top of 4.0.0-rc1 which has the same commits with Chris's for-linus, I looply ran btrfs/078 for 10 times(5 times with the default mkfs option while 5 with your mkfs option), works good so far.
So here it is,
fs/btrfs/extent-tree.c +0 -0
@@ -6033,7 +6033,7 @@ static int __btrfs_free_extent(struct
btrfs_trans_handle *trans,
}
btrfs_release_path(path);
- if (is_data) {
+ if (is_data && root_objectid != BTRFS_ROOT_TREE_OBJECTID) {
ret = btrfs_del_csums(trans, root, bytenr, num_bytes); if (ret) {
btrfs_abort_transaction(trans, extent_root, ret);
Thanks,
-liubo
Quoted 34 lines
[1]
[ 773.601170] BTRFS: assertion failed: list_empty(&cur_trans->dirty_bgs), file: fs/btrfs/transaction.c, line: 2007 [ 773.601170] ------------[ cut here ]------------ [ 773.601172] kernel BUG at fs/btrfs/ctree.h:4012! [ 773.601177] invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC [ 773.601183] Modules linked in: rpcsec_gss_krb5 loop btrfs [ 773.601187] CPU: 1 PID: 28350 Comm: fsstress Tainted: G W 3.19.0-rc5-default+ #233 [ 773.601189] Hardware name: Intel Corporation Santa Rosa platform/Matanzas, BIOS TSRSCRB1.86C.0047.B00.0610170821 10/17/06 [ 773.601191] task: ffff88004e220000 ti: ffff880076f30000 task.ti: ffff880076f30000 [ 773.601220] RIP: 0010:[<ffffffffa003824e>] [<ffffffffa003824e>] assfail.clone.0+0x1e/0x20 [btrfs] [ 773.601224] RSP: 0018:ffff880076f33e58 EFLAGS: 00010292 [ 773.601226] RAX: 0000000000000064 RBX: ffff8800789026e0 RCX: 0000000000000001 [ 773.601227] RDX: 0000000000000001 RSI: 0000000000000001 RDI: 0000000000000001 [ 773.601229] RBP: ffff880076f33e58 R08: 0000000000000001 R09: 0000000000000000 [ 773.601230] R10: 0000000000000001 R11: 0000000000000001 R12: ffff880075c3d000 [ 773.601232] R13: ffff880078927518 R14: ffff880078927380 R15: ffff88006bab63a8 [ 773.601234] FS: 00007fb829fd4700(0000) GS:ffff88007d400000(0000) knlGS:0000000000000000 [ 773.601236] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 773.601237] CR2: 00007f0fa86f3990 CR3: 0000000079102000 CR4: 00000000000007e0 [ 773.601239] Stack: [ 773.601244] ffff880076f33ed8 ffffffffa0039d9b ffff88007892738c 00ff880075c3d000 [ 773.601249] 0000000000000000 ffff88004e220000 ffff8800781dd730 ffff880075c3d000 [ 773.601254] ffff880075c3d000 ffff880075f7e868 0000000000000001 ffff8800781dc000 [ 773.601256] Call Trace: [ 773.601274] [<ffffffffa0039d9b>] btrfs_commit_transaction+0xb1b/0xb60 [btrfs] [ 773.601289] [<ffffffffa0004679>] btrfs_sync_fs+0x79/0x120 [btrfs] [ 773.601295] [<ffffffff811d3610>] ? SyS_tee+0x360/0x360 [ 773.601298] [<ffffffff811d3630>] sync_fs_one_sb+0x20/0x30 [ 773.601303] [<ffffffff811a5231>] iterate_supers+0xf1/0x100 [ 773.601307] [<ffffffff811d3965>] sys_sync+0x55/0x90 [ 773.601313] [<ffffffff81a9fc12>] system_call_fastpath+0x12/0x17
Quoted 44 lines · Liu Bo
Quoted 16 lines · David Sterba
Quoted 10 lines · Liu Bo
Quoted 8 lines · Josef Bacik
Dave could hit this assert consistently running btrfs/078. This is because when we update the block groups we could truncate the free space, which would try to delete the csums for that range and dirty the csum root. For this to happen we have to have already written out the csum root so it's kind of hard to hit this case. This patch fixes this by changing the logic to only write the dirty block groups if the
dirty_cowonly_rootslist is empty. This will get us the same effect as before since we add the extent root last, and will cover the case that we dirty some other root again but not the extent root. Thanks,Quoted 4 lines
Free space inode is NODATASUM, so its searching csum tree in
__btrfs_free_extent()is really unnecessary, by skipping that, csum tree won't be inserted intodirty_cowonly_rootslist again, so it also passed btrfs/078, at least on my box.Quoted 7 lines
I can hit the bug [1] even with Josef's patch, I'm can test your fix if you want.
MKFS_OPTIONS-- -O skinny-metadata,extref -m single -d single --mixed/dev/sdc1MOUNT_OPTIONS-- -o enospc_debug,space_cache,noatime/dev/sdc1/mnt/a2on top of 3.19-rc5 with Chris' for-linus.
I tested this fix on top of 4.0.0-rc1 which has the same commits with Chris's for-linus, I looply ran btrfs/078 for 10 times(5 times with the default mkfs option while 5 with your mkfs option), works good so far.
So here it is,
fs/btrfs/extent-tree.c +1
-1@@ -6033,7 +6033,7 @@ static int __btrfs_free_extent(structbtrfs_trans_handle *trans, }btrfs_release_path (path ); -if (is_data) { +if (is_data && root_objectid !=BTRFS_ROOT_TREE_OBJECTID ) { ret =btrfs_del_csums (trans, root, bytenr, num_bytes);if (ret) {
Quoted 3 lines
btrfs_abort_transaction(trans, extent_root, ret);
I have this locally but it was causing problems with xfstests (or there's unrelated problems that I just haven't noticed before), so I didn't send it out yet. My patch _should_ have fixed the problem, so if it didn't I want to figure out why before we go fixing other things. Thanks,
Josef
Quoted 16 lines · David Sterba
Quoted 10 lines · Liu Bo
Quoted 8 lines · Josef Bacik
Dave could hit this assert consistently running btrfs/078. This is because when we update the block groups we could truncate the free space, which would try to delete the csums for that range and dirty the csum root. For this to happen we have to have already written out the csum root so it's kind of hard to hit this case. This patch fixes this by changing the logic to only write the dirty block groups if the
dirty_cowonly_rootslist is empty. This will get us the same effect as before since we add the extent root last, and will cover the case that we dirty some other root again but not the extent root. Thanks,Quoted 4 lines
Free space inode is NODATASUM, so its searching csum tree in
__btrfs_free_extent()is really unnecessary, by skipping that, csum tree won't be inserted intodirty_cowonly_rootslist again, so it also passed btrfs/078, at least on my box.
Quoted 8 lines
I can hit the bug [1] even with Josef's patch, I'm can test your fix if you want.
MKFS_OPTIONS-- -O skinny-metadata,extref -m single -d single --mixed/dev/sdc1MOUNT_OPTIONS-- -o enospc_debug,space_cache,noatime/dev/sdc1/mnt/a2on top of 3.19-rc5 with Chris' for-linus.
Can you try this on top of this patch and send me the logs? Thanks,
Josef
fs/btrfs/ctree.c +1 -0
@@ -219,6 +219,7 @@ static void add_root_to_dirty_list(struct btrfs_root *root)spin_lock (&root->fs_info->trans_lock);if (!test_and_set_bit (BTRFS_ROOT_DIRTY , &root->state)) { +printk (KERN_ERR "dirtying root %llu\n" , root->objectid);/* Want the extent tree to be the last on the list */ if (root->objectid ==BTRFS_EXTENT_TREE_OBJECTID ) list_move_tail(&root->dirty_list,
fs/btrfs/extent-tree.c +2 -0
@@ -5369,6 +5369,8 @@ static int update_block_group(struct btrfs_trans_handle *trans,spin_lock (&trans->transaction->dirty_bgs_lock);if (list_empty (&cache->dirty_list)) { +printk (KERN_ERR "dirtying bg %llu\n" , + cache->key.objectid);list_add_tail (&cache->dirty_list, &trans->transaction->dirty_bgs);btrfs_get_block_group (cache);
fs/btrfs/transaction.c +14 -0
@@ -1027,6 +1027,10 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans, old_root_used =btrfs_root_used (&root->root_item); +printk (KERN_ERR "writing root %llu, dirty cowonly roots empty %d, " +"dirty bgs empty %d\n" , root->objectid, +list_empty (&fs_info->dirty_cowonly_roots), +list_empty (&trans->transaction->dirty_bgs));while (1 ) { old_root_bytenr =btrfs_root_bytenr (&root->root_item);
@@ -1050,6 +1054,7 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans, old_root_used =btrfs_root_used (&root->root_item);if (list_empty (&fs_info->dirty_cowonly_roots)) { +printk (KERN_ERR "writing dirty block groups\n" ); ret =btrfs_write_dirty_block_groups (trans, root);if (ret)return ret;
@@ -1123,6 +1128,7 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,return ret; } +printk (KERN_ERR "done writy dirty cowonly roots\n" );list_add_tail (&fs_info->extent_root->dirty_list, &trans->transaction->switch_commits);btrfs_after_dev_replace_commit (fs_info);
@@ -2000,6 +2006,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,switch_commit_roots (cur_trans, root->fs_info);assert_qgroups_uptodate (trans); +if (!list_empty (&cur_trans->dirty_bgs)) { +struct btrfs_block_group_cache *cache; + + cache =list_first_entry (&cur_trans->dirty_bgs, + struct btrfs_block_group_cache, + bg_list); +printk (KERN_ERR "bg %llu still dirty\n" , cache->key.objectid); + }ASSERT (list_empty (&cur_trans->dirty_bgs));update_super_roots (root);
Quoted 8 lines · Josef Bacik
Dave could hit this assert consistently running btrfs/078. This is because when we update the block groups we could truncate the free space, which would try to delete the csums for that range and dirty the csum root. For this to happen we have to have already written out the csum root so it's kind of hard to hit this case. This patch fixes this by changing the logic to only write the dirty block groups if the
dirty_cowonly_rootslist is empty. This will get us the same effect as before since we add the extent root last, and will cover the case that we dirty some other root again but not the extent root. Thanks,
Btw, in the title, s/dirty_bgs_list/dirty_bgs/ ;-)
Thanks,
-liubo
Quoted 52 lines
Reported-by David Sterba <[email protected]>Signed-off-by Josef Bacik <[email protected]>--- fs/btrfs/transaction.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)fs/btrfs/transaction.c +9
-3@@ -1023,16 +1023,22 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,u64 old_root_bytenr;u64 old_root_used;struct btrfs_root *tree_root = root->fs_info->tree_root; -bool extent_root = (root->objectid ==BTRFS_EXTENT_TREE_OBJECTID ); +struct btrfs_fs_info *fs_info = root->fs_info; old_root_used =btrfs_root_used (&root->root_item);btrfs_write_dirty_block_groups (trans, root);while (1 ) { old_root_bytenr =btrfs_root_bytenr (&root->root_item); + +/* +* We can only break out if our root matches the root item and +* we either have more roots to process or we have no more roots +* to process and there are no empty bgs. +*/ if (old_root_bytenr == root->node->start && old_root_used ==btrfs_root_used (&root->root_item) && - (!extent_root || + (!list_empty (&fs_info->dirty_cowonly_roots) ||list_empty (&trans->transaction->dirty_bgs)))break ;@@ -1044,7 +1050,7 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,return ret; old_root_used =btrfs_root_used (&root->root_item); -if (extent_root) { +if (list_empty (&fs_info->dirty_cowonly_roots)) { ret =btrfs_write_dirty_block_groups (trans, root);if (ret)return ret;Signature · 6 lines
1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html