summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2026-02-02 16:35:01 +0000
committerDavid Sterba <dsterba@suse.com>2026-04-07 18:55:53 +0200
commit40f2b11c1b7c593bbbfbf6bf333228ee53ed4050 (patch)
treed966e3101616e8121a1803e5631db1b97b8a9f87
parent574d93fc62e2b03ab39c8f92fb44ded89ca6274d (diff)
btrfs: don't allow log trees to consume global reserve or overcommit metadata
For a fsync we never reserve space in advance, we just start a transaction without reserving space and we use an empty block reserve for a log tree. We reserve space as we need while updating a log tree, we end up in btrfs_use_block_rsv() when reserving space for the allocation of a log tree extent buffer and we attempt first to reserve without flushing, and if that fails we attempt to consume from the global reserve or overcommit metadata. This makes us consume space that may be the last resort for a transaction commit to succeed, therefore increasing the chances for a transaction abort with -ENOSPC. So make btrfs_use_block_rsv() fail if we can't reserve metadata space for a log tree extent buffer allocation without flushing, making the fsync fallback to a transaction commit and avoid using critical space that could be the only resort for a transaction commit to succeed when we are in a critical space situation. Reviewed-by: Leo Martins <loemra.dev@gmail.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/block-rsv.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c
index 6064dd00d041..9efb3016ef11 100644
--- a/fs/btrfs/block-rsv.c
+++ b/fs/btrfs/block-rsv.c
@@ -541,6 +541,31 @@ try_reserve:
BTRFS_RESERVE_NO_FLUSH);
if (!ret)
return block_rsv;
+
+ /*
+ * If we are being used for updating a log tree, fail immediately, which
+ * makes the fsync fallback to a transaction commit.
+ *
+ * We don't want to consume from the global block reserve, as that is
+ * precious space that may be needed to do updates to some trees for
+ * which we don't reserve space during a transaction commit (update root
+ * items in the root tree, device stat items in the device tree and
+ * quota tree updates, see btrfs_init_root_block_rsv()), or to fallback
+ * to in case we did not reserve enough space to run delayed items,
+ * delayed references, or anything else we need in order to avoid a
+ * transaction abort.
+ *
+ * We also don't want to do a reservation in flush emergency mode, as
+ * we end up using metadata that could be critical to allow a
+ * transaction to complete successfully and therefore increase the
+ * chances for a transaction abort.
+ *
+ * Log trees are an optimization and should never consume from the
+ * global reserve or be allowed overcommitting metadata.
+ */
+ if (btrfs_root_id(root) == BTRFS_TREE_LOG_OBJECTID)
+ return ERR_PTR(ret);
+
/*
* If we couldn't reserve metadata bytes try and use some from
* the global reserve if its space type is the same as the global