btrfs: error out when COWing block using a stale transaction
authorFilipe Manana <fdmanana@suse.com>
Wed, 27 Sep 2023 11:09:21 +0000 (12:09 +0100)
committerDavid Sterba <dsterba@suse.com>
Tue, 3 Oct 2023 23:04:24 +0000 (01:04 +0200)
commit48774f3bf8b4dd3b1a0e155825c9ce48483db14c
treeb877898eabae1de4fa4097941799c05fd415d087
parentf8d1b011ca8c9d64ce32da431a8420635a96958a
btrfs: error out when COWing block using a stale transaction

At btrfs_cow_block() we have these checks to verify we are not using a
stale transaction (a past transaction with an unblocked state or higher),
and the only thing we do is to trigger a WARN with a message and a stack
trace. This however is a critical problem, highly unexpected and if it
happens it's most likely due to a bug, so we should error out and turn the
fs into error state so that such issue is much more easily noticed if it's
triggered.

The problem is critical because using such stale transaction will lead to
not persisting the extent buffer used for the COW operation, as allocating
a tree block adds the range of the respective extent buffer to the
->dirty_pages iotree of the transaction, and a stale transaction, in the
unlocked state or higher, will not flush dirty extent buffers anymore,
therefore resulting in not persisting the tree block and resource leaks
(not cleaning the dirty_pages iotree for example).

So do the following changes:

1) Return -EUCLEAN if we find a stale transaction;

2) Turn the fs into error state, with error -EUCLEAN, so that no
   transaction can be committed, and generate a stack trace;

3) Combine both conditions into a single if statement, as both are related
   and have the same error message;

4) Mark the check as unlikely, since this is not expected to ever happen.

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