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 20/21] xfs: support non-power-of-two rtextsize with exchange-range
Date: Fri, 30 Dec 2022 14:13:58 -0800 [thread overview]
Message-ID: <167243843816.699466.13150984573684791764.stgit@magnolia> (raw)
In-Reply-To: <167243843494.699466.5163281976943635014.stgit@magnolia>
From: Darrick J. Wong <djwong@kernel.org>
The VFS exchange-range alignment checks use (fast) bitmasks to perform
block alignment checks on the exchange parameters. Unfortunately,
bitmasks require that the alignment size be a power of two. This isn't
true for realtime devices, so we have to copy-pasta the VFS checks using
long division for this to work properly.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
fs/xfs/xfs_xchgrange.c | 102 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 91 insertions(+), 11 deletions(-)
diff --git a/fs/xfs/xfs_xchgrange.c b/fs/xfs/xfs_xchgrange.c
index 6a66d09099b0..ae030a6f607e 100644
--- a/fs/xfs/xfs_xchgrange.c
+++ b/fs/xfs/xfs_xchgrange.c
@@ -416,6 +416,86 @@ xfs_xchg_range_need_rt_conversion(
return xfs_inode_has_bigrtextents(ip);
}
+/*
+ * Check the alignment of an exchange request when the allocation unit size
+ * isn't a power of two. The VFS helpers use (fast) bitmask-based alignment
+ * checks, but here we have to use slow long division.
+ */
+static int
+xfs_xchg_range_check_rtalign(
+ struct xfs_inode *ip1,
+ struct xfs_inode *ip2,
+ const struct file_xchg_range *fxr)
+{
+ struct xfs_mount *mp = ip1->i_mount;
+ uint32_t rextbytes;
+ uint64_t length = fxr->length;
+ uint64_t blen;
+ loff_t size1, size2;
+
+ rextbytes = XFS_FSB_TO_B(mp, mp->m_sb.sb_rextsize);
+ size1 = i_size_read(VFS_I(ip1));
+ size2 = i_size_read(VFS_I(ip2));
+
+ /* The start of both ranges must be aligned to a rt extent. */
+ if (!isaligned_64(fxr->file1_offset, rextbytes) ||
+ !isaligned_64(fxr->file2_offset, rextbytes))
+ return -EINVAL;
+
+ /*
+ * If the caller asked for full files, check that the offset/length
+ * values cover all of both files.
+ */
+ if ((fxr->flags & FILE_XCHG_RANGE_FULL_FILES) &&
+ (fxr->file1_offset != 0 || fxr->file2_offset != 0 ||
+ fxr->length != size1 || fxr->length != size2))
+ return -EDOM;
+
+ if (fxr->flags & FILE_XCHG_RANGE_TO_EOF)
+ length = max_t(int64_t, size1 - fxr->file1_offset,
+ size2 - fxr->file2_offset);
+
+ /*
+ * If the user wanted us to exchange up to the infile's EOF, round up
+ * to the next rt extent boundary for this check. Do the same for the
+ * outfile.
+ *
+ * Otherwise, reject the range length if it's not rt extent aligned.
+ * We already confirmed the starting offsets' rt extent block
+ * alignment.
+ */
+ if (fxr->file1_offset + length == size1)
+ blen = roundup_64(size1, rextbytes) - fxr->file1_offset;
+ else if (fxr->file2_offset + length == size2)
+ blen = roundup_64(size2, rextbytes) - fxr->file2_offset;
+ else if (!isaligned_64(length, rextbytes))
+ return -EINVAL;
+ else
+ blen = length;
+
+ /* Don't allow overlapped exchanges within the same file. */
+ if (ip1 == ip2 &&
+ fxr->file2_offset + blen > fxr->file1_offset &&
+ fxr->file1_offset + blen > fxr->file2_offset)
+ return -EINVAL;
+
+ /*
+ * Ensure that we don't exchange a partial EOF rt extent into the
+ * middle of another file.
+ */
+ if (isaligned_64(length, rextbytes))
+ return 0;
+
+ blen = length;
+ if (fxr->file2_offset + length < size2)
+ blen = rounddown_64(blen, rextbytes);
+
+ if (fxr->file1_offset + blen < size1)
+ blen = rounddown_64(blen, rextbytes);
+
+ return blen == length ? 0 : -EINVAL;
+}
+
/* Prepare two files to have their data exchanged. */
int
xfs_xchg_range_prep(
@@ -426,6 +506,7 @@ xfs_xchg_range_prep(
{
struct xfs_inode *ip1 = XFS_I(file_inode(file1));
struct xfs_inode *ip2 = XFS_I(file_inode(file2));
+ unsigned int alloc_unit = xfs_inode_alloc_unitsize(ip2);
int error;
trace_xfs_xchg_range_prep(ip1, fxr, ip2, 0);
@@ -434,18 +515,17 @@ xfs_xchg_range_prep(
if (XFS_IS_REALTIME_INODE(ip1) != XFS_IS_REALTIME_INODE(ip2))
return -EINVAL;
- /*
- * The alignment checks in the VFS helpers cannot deal with allocation
- * units that are not powers of 2. This can happen with the realtime
- * volume if the extent size is set. Note that alignment checks are
- * skipped if FULL_FILES is set.
- */
- if (!(fxr->flags & FILE_XCHG_RANGE_FULL_FILES) &&
- !is_power_of_2(xfs_inode_alloc_unitsize(ip2)))
- return -EOPNOTSUPP;
+ /* Check non-power of two alignment issues, if necessary. */
+ if (XFS_IS_REALTIME_INODE(ip2) && !is_power_of_2(alloc_unit)) {
+ error = xfs_xchg_range_check_rtalign(ip1, ip2, fxr);
+ if (error)
+ return error;
- error = generic_xchg_file_range_prep(file1, file2, fxr,
- xfs_inode_alloc_unitsize(ip2));
+ /* Do the VFS checks with the regular block alignment. */
+ alloc_unit = ip1->i_mount->m_sb.sb_blocksize;
+ }
+
+ error = generic_xchg_file_range_prep(file1, file2, fxr, alloc_unit);
if (error || fxr->length == 0)
return error;
next prev parent reply other threads:[~2022-12-30 23:55 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <Y69Unb7KRM5awJoV@magnolia>
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 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 03/21] xfs: refactor non-power-of-two alignment checks 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 11/21] xfs: port xfs_swap_extents_rmap to our new code 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 08/21] xfs: enable xlog users to toggle atomic extent swapping Darrick J. Wong
2022-12-30 22:13 ` [PATCH 07/21] xfs: create deferred log items for " 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 ` [PATCH 18/21] xfs: condense symbolic links after an atomic swap 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 14/21] xfs: allow xfs_swap_range to use older extent swap algorithms 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 15/21] xfs: remove old swap extents implementation 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 ` Darrick J. Wong [this message]
2022-12-30 22:13 ` [PATCH 21/21] xfs: enable atomic swapext feature Darrick J. Wong
2022-12-30 22:13 ` [PATCH 19/21] xfs: make atomic extent swapping support realtime files 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=167243843816.699466.13150984573684791764.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