From: Dave Chinner <dgc@kernel.org>
To: linux-xfs@vger.kernel.org
Cc: cem@kernel.org
Subject: [PATCH 15/38] xfs: use zero-block transaction with xfs_trans_reserve_more_inode for COW holes
Date: Wed, 19 Aug 2026 10:12:18 +1000 [thread overview]
Message-ID: <20260819001442.1451892-16-dgc@kernel.org> (raw)
In-Reply-To: <20260819001442.1451892-1-dgc@kernel.org>
Change the COW transaction allocation strategy to use a zero-block
reservation at the top level and defer block reservation to the
callee that knows the actual extent state.
When xfs_reflink_allocate_cow() returns -EAGAIN, the ILOCK must be
dropped to allocate a transaction. Because the extent tree can change
while the ILOCK is not held, we cannot determine what extent type
will be found once we've regained the ILOCK. The callees will use
xfs_trans_reserve_more_inode() directly to reserve any blocks they
require before they start modifications. This allows ENOSPC to be
returned and the transaction cancelled safely if the block reservation
cannot be made.
In xfs_reflink_fill_cow_hole(), add an xfs_trans_reserve_more_inode()
call before xfs_bmapi_write() to reserve the blocks needed for the
COW extent allocation. The reservation is computed from the current
imap which is stable under the ILOCK. An ASSERT verifies the
transaction has not been dirtied, confirming it is safe to cancel
on ENOSPC.
Assisted-by: LLM
Signed-off-by: Dave Chinner <dgc@kernel.org>
---
fs/xfs/xfs_iomap.c | 28 +++++++++++-----------------
fs/xfs/xfs_reflink.c | 25 +++++++++++++++++++++++++
2 files changed, 36 insertions(+), 17 deletions(-)
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 017355372a44..777048e6a2ca 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -919,29 +919,23 @@ xfs_direct_write_cow_iomap_begin(
if (error == -EAGAIN) {
/*
* COW allocation needs a transaction. Drop the ILOCK and
- * allocate a transaction, which will re-acquire the ILOCK.
- * Then retry the imap lookup since the extent tree may have
- * changed while the ILOCK was not held.
+ * allocate a zero-block reservation transaction, which will
+ * re-acquire the ILOCK. We cannot determine what extent type
+ * will be found once we've regained the ILOCK, so the callees
+ * will use xfs_trans_reserve_more_inode() directly to reserve
+ * any blocks they require before they start modifications.
+ * This allows ENOSPC to be returned and the transaction
+ * cancelled safely if the block reservation cannot be made.
+ *
+ * Retry the imap lookup since the extent tree may have changed
+ * while the ILOCK was not held.
*/
- xfs_filblks_t resaligned;
- unsigned int dblocks, rblocks;
-
ASSERT(!tp);
xfs_iunlock(ip, *lockmode);
- resaligned = xfs_aligned_fsb_count(offset_fsb,
- end_fsb - offset_fsb, xfs_get_cowextsz_hint(ip));
- if (XFS_IS_REALTIME_INODE(ip)) {
- dblocks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
- rblocks = resaligned;
- } else {
- dblocks = XFS_DIOSTRAT_SPACE_RES(mp, resaligned);
- rblocks = 0;
- }
-
error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_write,
- dblocks, rblocks, false, &tp);
+ 0, 0, false, &tp);
if (error)
return error;
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index a3b4343fd882..373ce9fea2a8 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -437,6 +437,9 @@ xfs_reflink_fill_cow_hole(
bool *shared,
bool convert_now)
{
+ struct xfs_mount *mp = ip->i_mount;
+ xfs_filblks_t resaligned;
+ unsigned int dblocks = 0, rblocks = 0;
int nimaps;
int error;
bool found;
@@ -450,6 +453,28 @@ xfs_reflink_fill_cow_hole(
if (found)
goto convert;
+ /*
+ * Reserve blocks for the COW extent allocation. The transaction was
+ * allocated with a zero-block reservation because the caller could
+ * not determine the block reservation required until the extent
+ * state was known under the ILOCK. The transaction has not been
+ * dirtied yet, so on ENOSPC it can safely be cancelled by the caller.
+ */
+ ASSERT(!(tp->t_flags & XFS_TRANS_DIRTY));
+
+ resaligned = xfs_aligned_fsb_count(imap->br_startoff,
+ imap->br_blockcount, xfs_get_cowextsz_hint(ip));
+ if (XFS_IS_REALTIME_INODE(ip)) {
+ dblocks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
+ rblocks = resaligned;
+ } else {
+ dblocks = XFS_DIOSTRAT_SPACE_RES(mp, resaligned);
+ }
+
+ error = xfs_trans_reserve_more_inode(tp, ip, dblocks, rblocks, false);
+ if (error)
+ return error;
+
/* Allocate the entire reservation as unwritten blocks. */
nimaps = 1;
error = xfs_bmapi_write(tp, ip, imap->br_startoff,
--
2.55.0
next prev parent reply other threads:[~2026-08-19 0:15 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-19 0:12 [PATCH V2 00/38] XFS: Atomic multi-extent operations via rolling transactions Dave Chinner
2026-08-19 0:12 ` [PATCH 01/38] xfs: fix dirty transaction cancellation in xfs_bmapi_convert_one_delalloc Dave Chinner
2026-08-19 0:12 ` [PATCH 02/38] xfs: fix dirty transaction cancellation in xfs_attr_set Dave Chinner
2026-08-19 0:12 ` [PATCH 03/38] xfs: fix isize update in xfs_iomap_write_unwritten to track conversion progress Dave Chinner
2026-08-19 0:12 ` [PATCH 04/38] xfs: fix block reservation for zoned RT extent remapping Dave Chinner
2026-08-19 0:12 ` [PATCH 05/38] xfs: factor xfs_trans_reserve_blocks() from xfs_trans_reserve() Dave Chinner
2026-08-19 0:12 ` [PATCH 06/38] xfs: factor xfs_blockgc_start_flush() from xfs_blockgc_flush_all() Dave Chinner
2026-08-19 0:12 ` [PATCH 07/38] xfs: add async quota-targeted blockgc flush Dave Chinner
2026-08-19 0:12 ` [PATCH 08/38] xfs: add async blockgc retry to xfs_trans_reserve_more_inode() Dave Chinner
2026-08-19 0:12 ` [PATCH 09/38] xfs: factor out COW iomap handling from xfs_direct_write_iomap_begin() Dave Chinner
2026-08-19 0:12 ` [PATCH 10/38] xfs: plumb xfs_trans through xfs_reflink_allocate_cow and fill_cow_hole Dave Chinner
2026-08-19 0:12 ` [PATCH 11/38] xfs: teach xfs_reflink_fill_cow_hole() to use a caller-supplied transaction Dave Chinner
2026-08-19 0:12 ` [PATCH 12/38] xfs: add transaction retry infrastructure to xfs_direct_write_cow_iomap_begin Dave Chinner
2026-08-19 0:12 ` [PATCH 13/38] xfs: return -EAGAIN from xfs_reflink_allocate_cow for COW hole without transaction Dave Chinner
2026-08-19 0:12 ` [PATCH 14/38] xfs: remove internal transaction allocation from xfs_reflink_fill_cow_hole Dave Chinner
2026-08-19 0:12 ` Dave Chinner [this message]
2026-08-19 0:12 ` [PATCH 16/38] xfs: change *tp to **tpp in COW allocation call chain Dave Chinner
2026-08-19 0:12 ` [PATCH 17/38] xfs: convert xfs_reflink_fill_delalloc to use rolling transactions Dave Chinner
2026-08-19 0:12 ` [PATCH 18/38] xfs: return -EAGAIN from xfs_reflink_allocate_cow for all allocation cases Dave Chinner
2026-08-19 0:12 ` [PATCH 19/38] xfs: remove dead internal transaction allocation from xfs_reflink_fill_delalloc Dave Chinner
2026-08-19 0:12 ` [PATCH 20/38] xfs: plumb struct xfs_trans *tp into xfs_bmapi_convert_one_delalloc Dave Chinner
2026-08-19 0:12 ` [PATCH 21/38] xfs: use rolling transaction in xfs_bmapi_convert_delalloc Dave Chinner
2026-08-19 0:12 ` [PATCH 22/38] xfs: remove dead internal transaction path from xfs_bmapi_convert_one_delalloc Dave Chinner
2026-08-19 0:12 ` [PATCH 23/38] xfs: add block reservation renewal to xfs_defer_finish Dave Chinner
2026-08-19 0:12 ` [PATCH 24/38] xfs: factor out xfs_iomap_write_unwritten_one helper Dave Chinner
2026-08-19 0:12 ` [PATCH 25/38] xfs: convert xfs_iomap_write_unwritten to rolling transactions Dave Chinner
2026-08-19 0:12 ` [PATCH 26/38] xfs: plumb struct xfs_trans *tp into xfs_reflink_end_cow_extent Dave Chinner
2026-08-19 0:12 ` [PATCH 27/38] xfs: convert xfs_reflink_end_cow to rolling transactions Dave Chinner
2026-08-19 0:12 ` [PATCH 28/38] xfs: remove xfs_reflink_end_cow_extent wrapper and rename locked variant Dave Chinner
2026-08-19 0:12 ` [PATCH 29/38] xfs: convert xfs_zoned_end_io to rolling transactions Dave Chinner
2026-08-19 0:12 ` [PATCH 30/38] xfs: plumb struct xfs_trans *tp into xfs_iomap_write_direct Dave Chinner
2026-08-19 0:12 ` [PATCH 31/38] xfs: make xfs_iomap_write_direct fill in the iomap directly Dave Chinner
2026-08-19 0:12 ` [PATCH 32/38] xfs: plumb struct xfs_trans **tpp into xfs_direct_write_cow_iomap_begin Dave Chinner
2026-08-19 0:12 ` [PATCH 33/38] xfs: introduce struct xfs_direct_write_args for direct write call chain Dave Chinner
2026-08-19 0:12 ` [PATCH 34/38] xfs: convert xfs_direct_write_iomap_begin to use dwa struct throughout Dave Chinner
2026-08-19 0:12 ` [PATCH 35/38] xfs: restructure xfs_direct_write_iomap_begin with unified retry loop Dave Chinner
2026-08-19 0:12 ` [PATCH 36/38] xfs: clean up xfs_direct_write_cow_iomap_begin after restructure Dave Chinner
2026-08-19 0:12 ` [PATCH 37/38] xfs: make pNFS block allocation atomic with inode update Dave Chinner
2026-08-19 0:12 ` [PATCH 38/38] xfs: remove dead internal transaction path from xfs_iomap_write_direct Dave Chinner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260819001442.1451892-16-dgc@kernel.org \
--to=dgc@kernel.org \
--cc=cem@kernel.org \
--cc=linux-xfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.