From: "Darrick J. Wong" <djwong@kernel.org>
To: djwong@kernel.org
Cc: linux-xfs@vger.kernel.org, linux-fsdevel@vger.kernel.org,
linux-api@vger.kernel.org
Subject: [PATCH 14/21] xfs: allow xfs_swap_range to use older extent swap algorithms
Date: Fri, 30 Dec 2022 14:13:57 -0800 [thread overview]
Message-ID: <167243843727.699466.11955722742191147402.stgit@magnolia> (raw)
In-Reply-To: <167243843494.699466.5163281976943635014.stgit@magnolia>
From: Darrick J. Wong <djwong@kernel.org>
If userspace permits non-atomic swap operations, use the older code
paths to implement the same functionality.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
fs/xfs/xfs_bmap_util.c | 4 +-
fs/xfs/xfs_bmap_util.h | 4 ++
fs/xfs/xfs_xchgrange.c | 96 +++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 92 insertions(+), 12 deletions(-)
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 9d6337a05544..e8562c4de7eb 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -1261,7 +1261,7 @@ xfs_insert_file_space(
* reject and log the attempt. basically we are putting the responsibility on
* userspace to get this right.
*/
-static int
+int
xfs_swap_extents_check_format(
struct xfs_inode *ip, /* target inode */
struct xfs_inode *tip) /* tmp inode */
@@ -1403,7 +1403,7 @@ xfs_swap_change_owner(
}
/* Swap the extents of two files by swapping data forks. */
-STATIC int
+int
xfs_swap_extent_forks(
struct xfs_trans **tpp,
struct xfs_swapext_req *req)
diff --git a/fs/xfs/xfs_bmap_util.h b/fs/xfs/xfs_bmap_util.h
index 6888078f5c31..39c71da08403 100644
--- a/fs/xfs/xfs_bmap_util.h
+++ b/fs/xfs/xfs_bmap_util.h
@@ -69,6 +69,10 @@ int xfs_free_eofblocks(struct xfs_inode *ip);
int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
struct xfs_swapext *sx);
+struct xfs_swapext_req;
+int xfs_swap_extent_forks(struct xfs_trans **tpp, struct xfs_swapext_req *req);
+int xfs_swap_extents_check_format(struct xfs_inode *ip, struct xfs_inode *tip);
+
xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb);
xfs_extnum_t xfs_bmap_count_leaves(struct xfs_ifork *ifp, xfs_filblks_t *count);
diff --git a/fs/xfs/xfs_xchgrange.c b/fs/xfs/xfs_xchgrange.c
index 9966938134c0..2b7aedc49923 100644
--- a/fs/xfs/xfs_xchgrange.c
+++ b/fs/xfs/xfs_xchgrange.c
@@ -297,6 +297,33 @@ xfs_xchg_range_rele_log_assist(
xlog_drop_incompat_feat(mp->m_log, XLOG_INCOMPAT_FEAT_SWAPEXT);
}
+/* Decide if we can use the old data fork exchange code. */
+static inline bool
+xfs_xchg_use_forkswap(
+ const struct file_xchg_range *fxr,
+ struct xfs_inode *ip1,
+ struct xfs_inode *ip2)
+{
+ if (!(fxr->flags & FILE_XCHG_RANGE_NONATOMIC))
+ return false;
+ if (!(fxr->flags & FILE_XCHG_RANGE_FULL_FILES))
+ return false;
+ if (fxr->flags & FILE_XCHG_RANGE_TO_EOF)
+ return false;
+ if (fxr->file1_offset != 0 || fxr->file2_offset != 0)
+ return false;
+ if (fxr->length != ip1->i_disk_size)
+ return false;
+ if (fxr->length != ip2->i_disk_size)
+ return false;
+ return true;
+}
+
+enum xchg_strategy {
+ SWAPEXT = 1, /* xfs_swapext() */
+ FORKSWAP = 2, /* exchange forks */
+};
+
/* Exchange the contents of two files. */
int
xfs_xchg_range(
@@ -316,19 +343,13 @@ xfs_xchg_range(
};
struct xfs_trans *tp;
unsigned int qretry;
+ unsigned int flags = 0;
bool retried = false;
+ enum xchg_strategy strategy;
int error;
trace_xfs_xchg_range(ip1, fxr, ip2, xchg_flags);
- /*
- * This function only supports using log intent items (SXI items if
- * atomic exchange is required, or BUI items if not) to exchange file
- * data. The legacy whole-fork swap will be ported in a later patch.
- */
- if (!(xchg_flags & XFS_XCHG_RANGE_LOGGED) && !xfs_swapext_supported(mp))
- return -EOPNOTSUPP;
-
if (fxr->flags & FILE_XCHG_RANGE_TO_EOF)
req.req_flags |= XFS_SWAP_REQ_SET_SIZES;
if (fxr->flags & FILE_XCHG_RANGE_SKIP_FILE1_HOLES)
@@ -340,10 +361,25 @@ xfs_xchg_range(
if (error)
return error;
+ /*
+ * We haven't decided which exchange strategy we want to use yet, but
+ * here we must choose if we want freed blocks during the swap to be
+ * added to the transaction block reservation (RES_FDBLKS) or freed
+ * into the global fdblocks. The legacy fork swap mechanism doesn't
+ * free any blocks, so it doesn't require it. It is also the only
+ * option that works for older filesystems.
+ *
+ * The bmap log intent items that were added with rmap and reflink can
+ * change the bmbt shape, so the intent-based swap strategies require
+ * us to set RES_FDBLKS.
+ */
+ if (xfs_has_lazysbcount(mp))
+ flags |= XFS_TRANS_RES_FDBLKS;
+
retry:
/* Allocate the transaction, lock the inodes, and join them. */
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, req.resblks, 0,
- XFS_TRANS_RES_FDBLKS, &tp);
+ flags, &tp);
if (error)
return error;
@@ -386,6 +422,40 @@ xfs_xchg_range(
if (error)
goto out_trans_cancel;
+ if ((xchg_flags & XFS_XCHG_RANGE_LOGGED) || xfs_swapext_supported(mp)) {
+ /*
+ * xfs_swapext() uses deferred bmap log intent items to swap
+ * extents between file forks. If the atomic log swap feature
+ * is enabled, it will also use swapext log intent items to
+ * restart the operation in case of failure.
+ *
+ * This means that we can use it if we previously obtained
+ * permission from the log to use log-assisted atomic extent
+ * swapping; or if the fs supports rmap or reflink and the
+ * user said NONATOMIC.
+ */
+ strategy = SWAPEXT;
+ } else if (xfs_xchg_use_forkswap(fxr, ip1, ip2)) {
+ /*
+ * Exchange the file contents by using the old bmap fork
+ * exchange code, if we're a defrag tool doing a full file
+ * swap.
+ */
+ strategy = FORKSWAP;
+
+ error = xfs_swap_extents_check_format(ip2, ip1);
+ if (error) {
+ xfs_notice(mp,
+ "%s: inode 0x%llx format is incompatible for exchanging.",
+ __func__, ip2->i_ino);
+ goto out_trans_cancel;
+ }
+ } else {
+ /* We cannot exchange the file contents. */
+ error = -EOPNOTSUPP;
+ goto out_trans_cancel;
+ }
+
/* If we got this far on a dry run, all parameters are ok. */
if (fxr->flags & FILE_XCHG_RANGE_DRY_RUN)
goto out_trans_cancel;
@@ -398,7 +468,13 @@ xfs_xchg_range(
xfs_trans_ichgtime(tp, ip2,
XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
- xfs_swapext(tp, &req);
+ if (strategy == SWAPEXT) {
+ xfs_swapext(tp, &req);
+ } else {
+ error = xfs_swap_extent_forks(&tp, &req);
+ if (error)
+ goto out_trans_cancel;
+ }
/*
* Force the log to persist metadata updates if the caller or the
next prev parent reply other threads:[~2022-12-30 23:53 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-12-30 21:14 [NYE DELUGE 2/4] xfs: online repair in its entirety Darrick J. Wong
2022-12-30 22:12 ` [PATCHSET v24.0 0/7] xfs: stage repair information in pageable memory Darrick J. Wong
2022-12-30 22:12 ` [PATCH 5/7] xfs: speed up xfarray sort by sorting xfile page contents directly Darrick J. Wong
2022-12-30 22:12 ` [PATCH 3/7] xfs: convert xfarray insertion sort to heapsort using scratchpad memory Darrick J. Wong
2022-12-30 22:12 ` [PATCH 7/7] xfs: improve xfarray quicksort pivot Darrick J. Wong
2022-12-30 22:12 ` [PATCH 2/7] xfs: enable sorting of xfile-backed arrays Darrick J. Wong
2022-12-30 22:12 ` [PATCH 6/7] xfs: cache pages used for xfarray quicksort convergence Darrick J. Wong
2022-12-30 22:12 ` [PATCH 1/7] xfs: create a big array data structure Darrick J. Wong
2022-12-30 22:12 ` [PATCH 4/7] xfs: teach xfile to pass back direct-map pages to caller Darrick J. Wong
2022-12-30 22:13 ` [PATCHSET v24.0 0/7] xfs: support in-memory btrees Darrick J. Wong
2022-12-30 22:13 ` [PATCH 1/7] xfs: dump xfiles for debugging purposes Darrick J. Wong
2022-12-30 22:13 ` [PATCH 2/7] xfs: teach buftargs to maintain their own buffer hashtable Darrick J. Wong
2022-12-30 22:13 ` [PATCH 5/7] xfs: consolidate btree block allocation tracepoints Darrick J. Wong
2022-12-30 22:13 ` [PATCH 6/7] xfs: support in-memory btrees Darrick J. Wong
2022-12-30 22:13 ` [PATCH 3/7] xfs: support in-memory buffer cache targets Darrick J. Wong
2022-12-30 22:13 ` [PATCH 4/7] xfs: consolidate btree block freeing tracepoints Darrick J. Wong
2022-12-30 22:13 ` [PATCH 7/7] xfs: connect in-memory btrees to xfiles Darrick J. Wong
2022-12-30 22:13 ` [PATCHSET v24.0 00/21] xfs: atomic file updates Darrick J. Wong
2022-12-30 22:13 ` [PATCH 05/21] xfs: create a log incompat flag for atomic extent swapping Darrick J. Wong
2022-12-30 22:13 ` [PATCH 01/21] vfs: introduce new file range exchange ioctl Darrick J. Wong
2022-12-30 22:13 ` [PATCH 03/21] xfs: refactor non-power-of-two alignment checks Darrick J. Wong
2022-12-30 22:13 ` [PATCH 02/21] xfs: create a new helper to return a file's allocation unit Darrick J. Wong
2022-12-30 22:13 ` [PATCH 04/21] xfs: parameterize all the incompat log feature helpers Darrick J. Wong
2022-12-30 22:13 ` [PATCH 06/21] xfs: introduce a swap-extent log intent item Darrick J. Wong
2022-12-30 22:13 ` [PATCH 07/21] xfs: create deferred log items for extent swapping Darrick J. Wong
2022-12-30 22:13 ` [PATCH 08/21] xfs: enable xlog users to toggle atomic " Darrick J. Wong
2022-12-30 22:13 ` [PATCH 11/21] xfs: port xfs_swap_extents_rmap to our new code Darrick J. Wong
2022-12-30 22:13 ` [PATCH 10/21] xfs: add error injection to test swapext recovery Darrick J. Wong
2022-12-30 22:13 ` [PATCH 09/21] xfs: add a ->xchg_file_range handler Darrick J. Wong
2022-12-30 22:13 ` Darrick J. Wong [this message]
2022-12-30 22:13 ` [PATCH 18/21] xfs: condense symbolic links after an atomic swap Darrick J. Wong
2022-12-30 22:13 ` [PATCH 13/21] xfs: port xfs_swap_extent_forks to use xfs_swapext_req Darrick J. Wong
2022-12-30 22:13 ` [PATCH 17/21] xfs: condense directories after an atomic swap Darrick J. Wong
2022-12-30 22:13 ` [PATCH 16/21] xfs: condense extended attributes " Darrick J. Wong
2022-12-30 22:13 ` [PATCH 12/21] xfs: consolidate all of the xfs_swap_extent_forks code Darrick J. Wong
2022-12-30 22:13 ` [PATCH 15/21] xfs: remove old swap extents implementation Darrick J. Wong
2022-12-30 22:13 ` [PATCH 20/21] xfs: support non-power-of-two rtextsize with exchange-range Darrick J. Wong
2022-12-30 22:13 ` [PATCH 19/21] xfs: make atomic extent swapping support realtime files Darrick J. Wong
2022-12-30 22:13 ` [PATCH 21/21] xfs: enable atomic swapext feature Darrick J. Wong
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=167243843727.699466.11955722742191147402.stgit@magnolia \
--to=djwong@kernel.org \
--cc=linux-api@vger.kernel.org \
--cc=linux-fsdevel@vger.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).