All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Darrick J. Wong" <darrick.wong@oracle.com>
To: xfs <linux-xfs@vger.kernel.org>
Cc: Brian Foster <bfoster@redhat.com>, Christoph Hellwig <hch@infradead.org>
Subject: [PATCH] xfs: handle large CoW remapping requests
Date: Thu, 27 Apr 2017 14:27:54 -0700	[thread overview]
Message-ID: <20170427212754.GB19158@birch.djwong.org> (raw)

XFS transactions are constrained both by space and block reservation
limits and the fact that we have to avoid doing 64-bit divisions.  This
means that we can't remap more than 2^32 blocks at a time.  However,
file logical blocks are 64-bit in size, so if we encounter a huge remap
request we have to break it up into smaller pieces.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/xfs_reflink.c |   83 ++++++++++++++++++++++++++++++--------------------
 1 file changed, 49 insertions(+), 34 deletions(-)

diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index ffe6fe7..bb61bb2 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -675,49 +675,29 @@ xfs_reflink_cancel_cow_range(
 	return error;
 }
 
-/*
- * Remap parts of a file's data fork after a successful CoW.
- */
-int
-xfs_reflink_end_cow(
+/* Remap a particular subrange of a file. */
+STATIC int
+xfs_reflink_end_cow_range(
 	struct xfs_inode		*ip,
-	xfs_off_t			offset,
-	xfs_off_t			count)
+	struct xfs_ifork		*ifp,
+	xfs_fileoff_t			offset_fsb,
+	xfs_fileoff_t			end_fsb)
 {
-	struct xfs_ifork		*ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
-	struct xfs_bmbt_irec		got, del;
+	struct xfs_bmbt_irec		got;
+	struct xfs_bmbt_irec		del;
+	struct xfs_defer_ops		dfops;
 	struct xfs_trans		*tp;
-	xfs_fileoff_t			offset_fsb;
-	xfs_fileoff_t			end_fsb;
 	xfs_fsblock_t			firstfsb;
-	struct xfs_defer_ops		dfops;
-	int				error;
-	unsigned int			resblks;
 	xfs_filblks_t			rlen;
+	unsigned int			resblks;
 	xfs_extnum_t			idx;
-
-	trace_xfs_reflink_end_cow(ip, offset, count);
-
-	/* No COW extents?  That's easy! */
-	if (ifp->if_bytes == 0)
-		return 0;
-
-	offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset);
-	end_fsb = XFS_B_TO_FSB(ip->i_mount, offset + count);
+	int				error;
 
 	/*
-	 * Start a rolling transaction to switch the mappings.  We're
-	 * unlikely ever to have to remap 16T worth of single-block
-	 * extents, so just cap the worst case extent count to 2^32-1.
-	 * Stick a warning in just in case, and avoid 64-bit division.
+	 * Start a rolling transaction to switch the mappings.
+	 * Avoid 64-bit division.
 	 */
-	BUILD_BUG_ON(MAX_RW_COUNT > UINT_MAX);
-	if (end_fsb - offset_fsb > UINT_MAX) {
-		error = -EFSCORRUPTED;
-		xfs_force_shutdown(ip->i_mount, SHUTDOWN_CORRUPT_INCORE);
-		ASSERT(0);
-		goto out;
-	}
+	ASSERT(end_fsb - offset_fsb <= UINT_MAX);
 	resblks = XFS_NEXTENTADD_SPACE_RES(ip->i_mount,
 			(unsigned int)(end_fsb - offset_fsb),
 			XFS_DATA_FORK);
@@ -812,6 +792,41 @@ xfs_reflink_end_cow(
 }
 
 /*
+ * Remap parts of a file's data fork after a successful CoW.
+ */
+int
+xfs_reflink_end_cow(
+	struct xfs_inode		*ip,
+	xfs_off_t			offset,
+	xfs_off_t			count)
+{
+	struct xfs_ifork		*ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
+	xfs_fileoff_t			offset_fsb;
+	xfs_fileoff_t			end_fsb;
+	xfs_fileoff_t			opend;
+	int				error = 0;
+
+	trace_xfs_reflink_end_cow(ip, offset, count);
+
+	/* No COW extents?  That's easy! */
+	if (ifp->if_bytes == 0)
+		return 0;
+
+	offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset);
+	end_fsb = XFS_B_TO_FSB(ip->i_mount, offset + count);
+
+	while (offset_fsb < end_fsb) {
+		opend = min_t(xfs_fileoff_t, offset_fsb + UINT_MAX, end_fsb);
+		error = xfs_reflink_end_cow_range(ip, ifp, offset_fsb, opend);
+		if (error)
+			break;
+		offset_fsb = opend;
+	}
+
+	return error;
+}
+
+/*
  * Free leftover CoW reservations that didn't get cleaned out.
  */
 int

             reply	other threads:[~2017-04-27 21:28 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-04-27 21:27 Darrick J. Wong [this message]
2017-05-02  7:50 ` [PATCH] xfs: handle large CoW remapping requests Christoph Hellwig
2017-05-02 18:02   ` Darrick J. Wong
2017-05-04 11:54     ` Christoph Hellwig

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=20170427212754.GB19158@birch.djwong.org \
    --to=darrick.wong@oracle.com \
    --cc=bfoster@redhat.com \
    --cc=hch@infradead.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.