Commit c1112b6e authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Dave Chinner

xfs: optimize xfs_reflink_end_cow

Instead of doing a full extent list search for each extent that is
to be deleted using xfs_bmapi_read and then doing another one inside
of xfs_bunmapi_cow use the same scheme that xfs_bumapi uses:  look
up the last extent to be deleted and then use the extent index to
walk downward until we are outside the range to be deleted.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent 3e0ee78f
...@@ -633,25 +633,26 @@ xfs_reflink_end_cow( ...@@ -633,25 +633,26 @@ xfs_reflink_end_cow(
xfs_off_t offset, xfs_off_t offset,
xfs_off_t count) xfs_off_t count)
{ {
struct xfs_bmbt_irec irec; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
struct xfs_bmbt_irec uirec; struct xfs_bmbt_irec got, prev, del;
struct xfs_trans *tp; struct xfs_trans *tp;
xfs_fileoff_t offset_fsb; xfs_fileoff_t offset_fsb;
xfs_fileoff_t end_fsb; xfs_fileoff_t end_fsb;
xfs_filblks_t count_fsb;
xfs_fsblock_t firstfsb; xfs_fsblock_t firstfsb;
struct xfs_defer_ops dfops; struct xfs_defer_ops dfops;
int error; int error, eof = 0;
unsigned int resblks; unsigned int resblks;
xfs_filblks_t ilen;
xfs_filblks_t rlen; xfs_filblks_t rlen;
int nimaps; xfs_extnum_t idx;
trace_xfs_reflink_end_cow(ip, offset, count); 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); offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset);
end_fsb = XFS_B_TO_FSB(ip->i_mount, offset + count); end_fsb = XFS_B_TO_FSB(ip->i_mount, offset + count);
count_fsb = (xfs_filblks_t)(end_fsb - offset_fsb);
/* Start a rolling transaction to switch the mappings */ /* Start a rolling transaction to switch the mappings */
resblks = XFS_EXTENTADD_SPACE_RES(ip->i_mount, XFS_DATA_FORK); resblks = XFS_EXTENTADD_SPACE_RES(ip->i_mount, XFS_DATA_FORK);
...@@ -663,72 +664,65 @@ xfs_reflink_end_cow( ...@@ -663,72 +664,65 @@ xfs_reflink_end_cow(
xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, 0); xfs_trans_ijoin(tp, ip, 0);
/* Go find the old extent in the CoW fork. */ xfs_bmap_search_extents(ip, end_fsb - 1, XFS_COW_FORK, &eof, &idx,
while (offset_fsb < end_fsb) { &got, &prev);
/* Read extent from the source file */
nimaps = 1;
count_fsb = (xfs_filblks_t)(end_fsb - offset_fsb);
error = xfs_bmapi_read(ip, offset_fsb, count_fsb, &irec,
&nimaps, XFS_BMAPI_COWFORK);
if (error)
goto out_cancel;
ASSERT(nimaps == 1);
ASSERT(irec.br_startblock != DELAYSTARTBLOCK); /* If there is a hole at end_fsb - 1 go to the previous extent */
trace_xfs_reflink_cow_remap(ip, &irec); if (eof || got.br_startoff > end_fsb) {
ASSERT(idx > 0);
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, --idx), &got);
}
/* /* Walk backwards until we're out of the I/O range... */
* We can have a hole in the CoW fork if part of a directio while (got.br_startoff + got.br_blockcount > offset_fsb) {
* write is CoW but part of it isn't. del = got;
*/ xfs_trim_extent(&del, offset_fsb, end_fsb - offset_fsb);
rlen = ilen = irec.br_blockcount;
if (irec.br_startblock == HOLESTARTBLOCK) /* Extent delete may have bumped idx forward */
if (!del.br_blockcount) {
idx--;
goto next_extent; goto next_extent;
}
ASSERT(!isnullstartblock(got.br_startblock));
/* Unmap the old blocks in the data fork. */ /* Unmap the old blocks in the data fork. */
while (rlen) { xfs_defer_init(&dfops, &firstfsb);
xfs_defer_init(&dfops, &firstfsb); rlen = del.br_blockcount;
error = __xfs_bunmapi(tp, ip, irec.br_startoff, error = __xfs_bunmapi(tp, ip, del.br_startoff, &rlen, 0, 1,
&rlen, 0, 1, &firstfsb, &dfops); &firstfsb, &dfops);
if (error) if (error)
goto out_defer; goto out_defer;
/*
* Trim the extent to whatever got unmapped.
* Remember, bunmapi works backwards.
*/
uirec.br_startblock = irec.br_startblock + rlen;
uirec.br_startoff = irec.br_startoff + rlen;
uirec.br_blockcount = irec.br_blockcount - rlen;
irec.br_blockcount = rlen;
trace_xfs_reflink_cow_remap_piece(ip, &uirec);
/* Free the CoW orphan record. */ /* Trim the extent to whatever got unmapped. */
error = xfs_refcount_free_cow_extent(tp->t_mountp, if (rlen) {
&dfops, uirec.br_startblock, xfs_trim_extent(&del, del.br_startoff + rlen,
uirec.br_blockcount); del.br_blockcount - rlen);
if (error) }
goto out_defer; trace_xfs_reflink_cow_remap(ip, &del);
/* Map the new blocks into the data fork. */ /* Free the CoW orphan record. */
error = xfs_bmap_map_extent(tp->t_mountp, &dfops, error = xfs_refcount_free_cow_extent(tp->t_mountp, &dfops,
ip, &uirec); del.br_startblock, del.br_blockcount);
if (error) if (error)
goto out_defer; goto out_defer;
/* Remove the mapping from the CoW fork. */ /* Map the new blocks into the data fork. */
error = xfs_bunmapi_cow(ip, &uirec); error = xfs_bmap_map_extent(tp->t_mountp, &dfops, ip, &del);
if (error) if (error)
goto out_defer; goto out_defer;
error = xfs_defer_finish(&tp, &dfops, ip); /* Remove the mapping from the CoW fork. */
if (error) xfs_bmap_del_extent_cow(ip, &idx, &got, &del);
goto out_defer;
} error = xfs_defer_finish(&tp, &dfops, ip);
if (error)
goto out_defer;
next_extent: next_extent:
/* Roll on... */ if (idx < 0)
offset_fsb = irec.br_startoff + ilen; break;
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &got);
} }
error = xfs_trans_commit(tp); error = xfs_trans_commit(tp);
...@@ -739,7 +733,6 @@ xfs_reflink_end_cow( ...@@ -739,7 +733,6 @@ xfs_reflink_end_cow(
out_defer: out_defer:
xfs_defer_cancel(&dfops); xfs_defer_cancel(&dfops);
out_cancel:
xfs_trans_cancel(tp); xfs_trans_cancel(tp);
xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(ip, XFS_ILOCK_EXCL);
out: out:
......
...@@ -3356,7 +3356,6 @@ DEFINE_INODE_IREC_EVENT(xfs_reflink_trim_irec); ...@@ -3356,7 +3356,6 @@ DEFINE_INODE_IREC_EVENT(xfs_reflink_trim_irec);
DEFINE_SIMPLE_IO_EVENT(xfs_reflink_cancel_cow_range); DEFINE_SIMPLE_IO_EVENT(xfs_reflink_cancel_cow_range);
DEFINE_SIMPLE_IO_EVENT(xfs_reflink_end_cow); DEFINE_SIMPLE_IO_EVENT(xfs_reflink_end_cow);
DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_remap); DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_remap);
DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_remap_piece);
DEFINE_INODE_ERROR_EVENT(xfs_reflink_allocate_cow_range_error); DEFINE_INODE_ERROR_EVENT(xfs_reflink_allocate_cow_range_error);
DEFINE_INODE_ERROR_EVENT(xfs_reflink_cancel_cow_range_error); DEFINE_INODE_ERROR_EVENT(xfs_reflink_cancel_cow_range_error);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment