diff options
author | Liu Bo <bo.li.liu@oracle.com> | 2018-01-25 11:02:51 -0700 |
---|---|---|
committer | Sasha Levin <alexander.levin@microsoft.com> | 2018-03-04 10:28:23 -0500 |
commit | 1b555cf3a4d7404c659606606b873e5a5786ea6e (patch) | |
tree | 08ba694dabdec9fd7381a58c8f93562c5cf84119 /fs | |
parent | 9ba95b32566a8eac13233bfb4d116a857b9e5790 (diff) |
Btrfs: fix crash due to not cleaning up tree log block's dirty bits
[ Upstream commit 1846430c24d66e85cc58286b3319c82cd54debb2 ]
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: 681ae50917df ("Btrfs: cleanup reserved space when freeing tree log on error")
Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
Reviewed-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/tree-log.c | 9 |
1 files changed, 9 insertions, 0 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 6ee954c62fe6..3cd1abf692dd 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2343,6 +2343,9 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, next); btrfs_wait_tree_block_writeback(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 != @@ -2422,6 +2425,9 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans, next); btrfs_wait_tree_block_writeback(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); @@ -2498,6 +2504,9 @@ static int walk_log_tree(struct btrfs_trans_handle *trans, clean_tree_block(trans, log->fs_info, next); btrfs_wait_tree_block_writeback(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 != |