Linux userland API discussions
 help / color / mirror / Atom feed
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;
 


  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