diff options
author | Filipe Manana <fdmanana@suse.com> | 2023-06-08 11:27:45 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-07-27 08:56:46 +0200 |
commit | 951b87d8ba6afadf4da6085f2f00531ced02c160 (patch) | |
tree | b0b296e312fd0bdd3f5fd978caff107e58615423 | |
parent | d40be032ecd8ee1ca033bee43c7755d21fb4d72a (diff) | |
download | linux-stable-951b87d8ba6afadf4da6085f2f00531ced02c160.tar.gz linux-stable-951b87d8ba6afadf4da6085f2f00531ced02c160.tar.bz2 linux-stable-951b87d8ba6afadf4da6085f2f00531ced02c160.zip |
btrfs: abort transaction at update_ref_for_cow() when ref count is zero
[ Upstream commit eced687e224eb3cc5a501cf53ad9291337c8dbc5 ]
At update_ref_for_cow() we are calling btrfs_handle_fs_error() if we find
that the extent buffer has an unexpected ref count of zero, however we can
simply use btrfs_abort_transaction(), which achieves the same purposes: to
turn the fs to error state, abort the current transaction and turn the fs
to RO mode as well. Besides that, btrfs_abort_transaction() also prints a
stack trace which makes it more useful.
Also, as this is a very unexpected situation, indicating a serious
corruption/inconsistency, tag the if branch as 'unlikely', set the error
code to -EUCLEAN instead of -EROFS, and log an explicit message.
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r-- | fs/btrfs/ctree.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 4912d624ca3d..886e661a218f 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -417,9 +417,13 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, &refs, &flags); if (ret) return ret; - if (refs == 0) { - ret = -EROFS; - btrfs_handle_fs_error(fs_info, ret, NULL); + if (unlikely(refs == 0)) { + btrfs_crit(fs_info, + "found 0 references for tree block at bytenr %llu level %d root %llu", + buf->start, btrfs_header_level(buf), + btrfs_root_id(root)); + ret = -EUCLEAN; + btrfs_abort_transaction(trans, ret); return ret; } } else { |