Commit 16199ad9 authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba
Browse files

btrfs: do not abort transaction on failure to write log tree when syncing log

When syncing the log, if we fail to write log tree extent buffers, we mark
the log for a full commit and abort the transaction. However we don't need
to abort the transaction, all we really need to do is to make sure no one
can commit a superblock pointing to new log tree roots. Just because we
got a failure writing extent buffers for a log tree, it does not mean we
will also fail to do a transaction commit.

One particular case is if due to a bug somewhere, when writing log tree
extent buffers, the tree checker detects some corruption and the writeout
fails because of that. Aborting the transaction can be very disruptive for
a user, specially if the issue happened on a root filesystem. One example
is the scenario in the Link tag below, where an isolated corruption on log
tree leaves was causing transaction aborts when syncing the log.

Link: https://lore.kernel.org/linux-btrfs/ae169fc6-f504-28f0-a098-6fa6a4dfb612@leemhuis.info/


CC: stable@vger.kernel.org # 5.15+
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 94cd63ae
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -367,7 +367,14 @@ static int csum_one_extent_buffer(struct extent_buffer *eb)
	btrfs_print_tree(eb, 0);
	btrfs_err(fs_info, "block=%llu write time tree block corruption detected",
		  eb->start);
	WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
	/*
	 * Be noisy if this is an extent buffer from a log tree. We don't abort
	 * a transaction in case there's a bad log tree extent buffer, we just
	 * fallback to a transaction commit. Still we want to know when there is
	 * a bad log tree extent buffer, as that may signal a bug somewhere.
	 */
	WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG) ||
		btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID);
	return ret;
}

+0 −2
Original line number Diff line number Diff line
@@ -2980,7 +2980,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
		ret = 0;
	if (ret) {
		blk_finish_plug(&plug);
		btrfs_abort_transaction(trans, ret);
		btrfs_set_log_full_commit(trans);
		mutex_unlock(&root->log_mutex);
		goto out;
@@ -3112,7 +3111,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
		goto out_wake_log_root;
	} else if (ret) {
		btrfs_set_log_full_commit(trans);
		btrfs_abort_transaction(trans, ret);
		mutex_unlock(&log_root_tree->log_mutex);
		goto out_wake_log_root;
	}