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
next 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.