Commit 0f4adc14 authored by Liu Bo's avatar Liu Bo Committed by Greg Kroah-Hartman

Btrfs: fix crash due to not cleaning up tree log block's dirty bits

commit 1846430c upstream.

In cases that the whole fs flips into readonly status due to failures in
critical sections, then log tree's blocks are still dirty, and this leads
to a crash during umount time, the crash is about use-after-free,

umount
 -> close_ctree
    -> stop workers
    -> iput(btree_inode)
       -> iput_final
          -> write_inode_now
	     -> ...
	       -> queue job on stop'd workers

cc: <stable@vger.kernel.org> v3.12+
Fixes: 681ae509 ("Btrfs: cleanup reserved space when freeing tree log on error")
Signed-off-by: default avatarLiu Bo <bo.li.liu@oracle.com>
Reviewed-by: default avatarJosef Bacik <jbacik@fb.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ecd72fd6
...@@ -2463,6 +2463,9 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, ...@@ -2463,6 +2463,9 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
next); next);
btrfs_wait_tree_block_writeback(next); btrfs_wait_tree_block_writeback(next);
btrfs_tree_unlock(next); btrfs_tree_unlock(next);
} else {
if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
clear_extent_buffer_dirty(next);
} }
WARN_ON(root_owner != WARN_ON(root_owner !=
...@@ -2542,6 +2545,9 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans, ...@@ -2542,6 +2545,9 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
next); next);
btrfs_wait_tree_block_writeback(next); btrfs_wait_tree_block_writeback(next);
btrfs_tree_unlock(next); btrfs_tree_unlock(next);
} else {
if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
clear_extent_buffer_dirty(next);
} }
WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID); WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
...@@ -2618,6 +2624,9 @@ static int walk_log_tree(struct btrfs_trans_handle *trans, ...@@ -2618,6 +2624,9 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
clean_tree_block(trans, log->fs_info, next); clean_tree_block(trans, log->fs_info, next);
btrfs_wait_tree_block_writeback(next); btrfs_wait_tree_block_writeback(next);
btrfs_tree_unlock(next); btrfs_tree_unlock(next);
} else {
if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
clear_extent_buffer_dirty(next);
} }
WARN_ON(log->root_key.objectid != WARN_ON(log->root_key.objectid !=
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment