btrfs: abort transaction at update_ref_for_cow() when ref count is zero
authorFilipe Manana <fdmanana@suse.com>
Thu, 8 Jun 2023 10:27:45 +0000 (11:27 +0100)
committerDavid Sterba <dsterba@suse.com>
Mon, 19 Jun 2023 11:59:39 +0000 (13:59 +0200)
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>
fs/btrfs/ctree.c

index 00eea29..b643bd8 100644 (file)
@@ -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 {