Patch "btrfs: error out when COWing block using a stale transaction" has been added to the 6.5-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    btrfs: error out when COWing block using a stale transaction

to the 6.5-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     btrfs-error-out-when-cowing-block-using-a-stale-tran.patch
and it can be found in the queue-6.5 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 56ca3238a6c6f1e8c8c98f67fe375b2e1437a521
Author: Filipe Manana <fdmanana@xxxxxxxx>
Date:   Wed Sep 27 12:09:21 2023 +0100

    btrfs: error out when COWing block using a stale transaction
    
    [ Upstream commit 48774f3bf8b4dd3b1a0e155825c9ce48483db14c ]
    
    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@xxxxxxxx>
    Reviewed-by: David Sterba <dsterba@xxxxxxxx>
    Signed-off-by: David Sterba <dsterba@xxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index a4cb4b6429870..7afd0a6495f37 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -686,14 +686,22 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
 		btrfs_err(fs_info,
 			"COW'ing blocks on a fs root that's being dropped");
 
-	if (trans->transaction != fs_info->running_transaction)
-		WARN(1, KERN_CRIT "trans %llu running %llu\n",
-		       trans->transid,
-		       fs_info->running_transaction->transid);
-
-	if (trans->transid != fs_info->generation)
-		WARN(1, KERN_CRIT "trans %llu running %llu\n",
-		       trans->transid, fs_info->generation);
+	/*
+	 * COWing must happen through a running transaction, which always
+	 * matches the current fs generation (it's a transaction with a state
+	 * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
+	 * into error state to prevent the commit of any transaction.
+	 */
+	if (unlikely(trans->transaction != fs_info->running_transaction ||
+		     trans->transid != fs_info->generation)) {
+		btrfs_abort_transaction(trans, -EUCLEAN);
+		btrfs_crit(fs_info,
+"unexpected transaction when attempting to COW block %llu on root %llu, transaction %llu running transaction %llu fs generation %llu",
+			   buf->start, btrfs_root_id(root), trans->transid,
+			   fs_info->running_transaction->transid,
+			   fs_info->generation);
+		return -EUCLEAN;
+	}
 
 	if (!should_cow_block(trans, root, buf)) {
 		*cow_ret = buf;



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux