summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ctree.c
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2023-06-08 11:27:45 +0100
committerDavid Sterba <dsterba@suse.com>2023-06-19 13:59:39 +0200
commiteced687e224eb3cc5a501cf53ad9291337c8dbc5 (patch)
tree7bdec09ce305a166fe8563af7eb454bdd1bec3ee /fs/btrfs/ctree.c
parent725026ed593f1b6da66fe7e3777cd891dbf7343f (diff)
downloadlinux-eced687e224eb3cc5a501cf53ad9291337c8dbc5.tar.gz
linux-eced687e224eb3cc5a501cf53ad9291337c8dbc5.tar.bz2
linux-eced687e224eb3cc5a501cf53ad9291337c8dbc5.zip
btrfs: abort transaction at update_ref_for_cow() when ref count is zero
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>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r--fs/btrfs/ctree.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 00eea2925d1d..b643bd8656bf 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -421,9 +421,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 {