summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_reflink.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_reflink.c')
-rw-r--r--fs/xfs/xfs_reflink.c173
1 files changed, 38 insertions, 135 deletions
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 592fb2071a03..38f405415b88 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -157,12 +157,12 @@ xfs_reflink_find_shared(
if (!agbp)
return -ENOMEM;
- cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
+ cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
error = xfs_refcount_find_shared(cur, agbno, aglen, fbno, flen,
find_end_of_shared);
- xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+ xfs_btree_del_cursor(cur, error);
xfs_trans_brelse(tp, agbp);
return error;
@@ -312,10 +312,8 @@ xfs_reflink_convert_cow_extent(
struct xfs_inode *ip,
struct xfs_bmbt_irec *imap,
xfs_fileoff_t offset_fsb,
- xfs_filblks_t count_fsb,
- struct xfs_defer_ops *dfops)
+ xfs_filblks_t count_fsb)
{
- xfs_fsblock_t first_block = NULLFSBLOCK;
int nimaps = 1;
if (imap->br_state == XFS_EXT_NORM)
@@ -326,8 +324,8 @@ xfs_reflink_convert_cow_extent(
if (imap->br_blockcount == 0)
return 0;
return xfs_bmapi_write(NULL, ip, imap->br_startoff, imap->br_blockcount,
- XFS_BMAPI_COWFORK | XFS_BMAPI_CONVERT, &first_block,
- 0, imap, &nimaps, dfops);
+ XFS_BMAPI_COWFORK | XFS_BMAPI_CONVERT, 0, imap,
+ &nimaps);
}
/* Convert all of the unwritten CoW extents in a file's range to real ones. */
@@ -342,8 +340,6 @@ xfs_reflink_convert_cow(
xfs_fileoff_t end_fsb = XFS_B_TO_FSB(mp, offset + count);
xfs_filblks_t count_fsb = end_fsb - offset_fsb;
struct xfs_bmbt_irec imap;
- struct xfs_defer_ops dfops;
- xfs_fsblock_t first_block = NULLFSBLOCK;
int nimaps = 1, error = 0;
ASSERT(count != 0);
@@ -351,8 +347,7 @@ xfs_reflink_convert_cow(
xfs_ilock(ip, XFS_ILOCK_EXCL);
error = xfs_bmapi_write(NULL, ip, offset_fsb, count_fsb,
XFS_BMAPI_COWFORK | XFS_BMAPI_CONVERT |
- XFS_BMAPI_CONVERT_ONLY, &first_block, 0, &imap, &nimaps,
- &dfops);
+ XFS_BMAPI_CONVERT_ONLY, 0, &imap, &nimaps);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
return error;
}
@@ -369,9 +364,7 @@ xfs_reflink_allocate_cow(
xfs_fileoff_t offset_fsb = imap->br_startoff;
xfs_filblks_t count_fsb = imap->br_blockcount;
struct xfs_bmbt_irec got;
- struct xfs_defer_ops dfops;
struct xfs_trans *tp = NULL;
- xfs_fsblock_t first_block;
int nimaps, error = 0;
bool trimmed;
xfs_filblks_t resaligned;
@@ -430,23 +423,18 @@ retry:
xfs_trans_ijoin(tp, ip, 0);
- xfs_defer_init(&dfops, &first_block);
nimaps = 1;
/* Allocate the entire reservation as unwritten blocks. */
error = xfs_bmapi_write(tp, ip, imap->br_startoff, imap->br_blockcount,
- XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC, &first_block,
- resblks, imap, &nimaps, &dfops);
+ XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC,
+ resblks, imap, &nimaps);
if (error)
- goto out_bmap_cancel;
+ goto out_trans_cancel;
xfs_inode_set_cowblocks_tag(ip);
/* Finish up. */
- error = xfs_defer_finish(&tp, &dfops);
- if (error)
- goto out_bmap_cancel;
-
error = xfs_trans_commit(tp);
if (error)
return error;
@@ -458,10 +446,8 @@ retry:
if (nimaps == 0)
return -ENOSPC;
convert:
- return xfs_reflink_convert_cow_extent(ip, imap, offset_fsb, count_fsb,
- &dfops);
-out_bmap_cancel:
- xfs_defer_cancel(&dfops);
+ return xfs_reflink_convert_cow_extent(ip, imap, offset_fsb, count_fsb);
+out_trans_cancel:
xfs_trans_unreserve_quota_nblks(tp, ip, (long)resblks, 0,
XFS_QMOPT_RES_REGBLKS);
out:
@@ -471,69 +457,6 @@ out:
}
/*
- * Find the CoW reservation for a given byte offset of a file.
- */
-bool
-xfs_reflink_find_cow_mapping(
- struct xfs_inode *ip,
- xfs_off_t offset,
- struct xfs_bmbt_irec *imap)
-{
- struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
- xfs_fileoff_t offset_fsb;
- struct xfs_bmbt_irec got;
- struct xfs_iext_cursor icur;
-
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED));
-
- if (!xfs_is_reflink_inode(ip))
- return false;
- offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset);
- if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &icur, &got))
- return false;
- if (got.br_startoff > offset_fsb)
- return false;
-
- trace_xfs_reflink_find_cow_mapping(ip, offset, 1, XFS_IO_OVERWRITE,
- &got);
- *imap = got;
- return true;
-}
-
-/*
- * Trim an extent to end at the next CoW reservation past offset_fsb.
- */
-void
-xfs_reflink_trim_irec_to_next_cow(
- struct xfs_inode *ip,
- xfs_fileoff_t offset_fsb,
- struct xfs_bmbt_irec *imap)
-{
- struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
- struct xfs_bmbt_irec got;
- struct xfs_iext_cursor icur;
-
- if (!xfs_is_reflink_inode(ip))
- return;
-
- /* Find the extent in the CoW fork. */
- if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &icur, &got))
- return;
-
- /* This is the extent before; try sliding up one. */
- if (got.br_startoff < offset_fsb) {
- if (!xfs_iext_next_extent(ifp, &icur, &got))
- return;
- }
-
- if (got.br_startoff >= imap->br_startoff + imap->br_blockcount)
- return;
-
- imap->br_blockcount = got.br_startoff - imap->br_startoff;
- trace_xfs_reflink_trim_irec(ip, imap);
-}
-
-/*
* Cancel CoW reservations for some block range of an inode.
*
* If cancel_real is true this function cancels all COW fork extents for the
@@ -553,11 +476,9 @@ xfs_reflink_cancel_cow_blocks(
struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
struct xfs_bmbt_irec got, del;
struct xfs_iext_cursor icur;
- xfs_fsblock_t firstfsb;
- struct xfs_defer_ops dfops;
int error = 0;
- if (!xfs_is_reflink_inode(ip))
+ if (!xfs_inode_has_cow_data(ip))
return 0;
if (!xfs_iext_lookup_extent_before(ip, ifp, &end_fsb, &icur, &got))
return 0;
@@ -581,26 +502,21 @@ xfs_reflink_cancel_cow_blocks(
if (error)
break;
} else if (del.br_state == XFS_EXT_UNWRITTEN || cancel_real) {
- xfs_defer_init(&dfops, &firstfsb);
+ ASSERT((*tpp)->t_firstblock == NULLFSBLOCK);
/* Free the CoW orphan record. */
- error = xfs_refcount_free_cow_extent(ip->i_mount,
- &dfops, del.br_startblock,
- del.br_blockcount);
+ error = xfs_refcount_free_cow_extent(*tpp,
+ del.br_startblock, del.br_blockcount);
if (error)
break;
- xfs_bmap_add_free(ip->i_mount, &dfops,
- del.br_startblock, del.br_blockcount,
- NULL);
+ xfs_bmap_add_free(*tpp, del.br_startblock,
+ del.br_blockcount, NULL);
/* Roll the transaction */
- xfs_defer_ijoin(&dfops, ip);
- error = xfs_defer_finish(tpp, &dfops);
- if (error) {
- xfs_defer_cancel(&dfops);
+ error = xfs_defer_finish(tpp);
+ if (error)
break;
- }
/* Remove the mapping from the CoW fork. */
xfs_bmap_del_extent_cow(ip, &icur, &got, &del);
@@ -623,7 +539,6 @@ next_extent:
/* clear tag if cow fork is emptied */
if (!ifp->if_bytes)
xfs_inode_clear_cowblocks_tag(ip);
-
return error;
}
@@ -696,8 +611,6 @@ xfs_reflink_end_cow(
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;
@@ -764,12 +677,11 @@ xfs_reflink_end_cow(
goto prev_extent;
/* Unmap the old blocks in the data fork. */
- xfs_defer_init(&dfops, &firstfsb);
+ ASSERT(tp->t_firstblock == NULLFSBLOCK);
rlen = del.br_blockcount;
- error = __xfs_bunmapi(tp, ip, del.br_startoff, &rlen, 0, 1,
- &firstfsb, &dfops);
+ error = __xfs_bunmapi(tp, ip, del.br_startoff, &rlen, 0, 1);
if (error)
- goto out_defer;
+ goto out_cancel;
/* Trim the extent to whatever got unmapped. */
if (rlen) {
@@ -779,15 +691,15 @@ xfs_reflink_end_cow(
trace_xfs_reflink_cow_remap(ip, &del);
/* Free the CoW orphan record. */
- error = xfs_refcount_free_cow_extent(tp->t_mountp, &dfops,
- del.br_startblock, del.br_blockcount);
+ error = xfs_refcount_free_cow_extent(tp, del.br_startblock,
+ del.br_blockcount);
if (error)
- goto out_defer;
+ goto out_cancel;
/* Map the new blocks into the data fork. */
- error = xfs_bmap_map_extent(tp->t_mountp, &dfops, ip, &del);
+ error = xfs_bmap_map_extent(tp, ip, &del);
if (error)
- goto out_defer;
+ goto out_cancel;
/* Charge this new data fork mapping to the on-disk quota. */
xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_DELBCOUNT,
@@ -796,10 +708,9 @@ xfs_reflink_end_cow(
/* Remove the mapping from the CoW fork. */
xfs_bmap_del_extent_cow(ip, &icur, &got, &del);
- xfs_defer_ijoin(&dfops, ip);
- error = xfs_defer_finish(&tp, &dfops);
+ error = xfs_defer_finish(&tp);
if (error)
- goto out_defer;
+ goto out_cancel;
if (!xfs_iext_get_extent(ifp, &icur, &got))
break;
continue;
@@ -814,8 +725,6 @@ prev_extent:
goto out;
return 0;
-out_defer:
- xfs_defer_cancel(&dfops);
out_cancel:
xfs_trans_cancel(tp);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -1070,9 +979,7 @@ xfs_reflink_remap_extent(
struct xfs_mount *mp = ip->i_mount;
bool real_extent = xfs_bmap_is_real_extent(irec);
struct xfs_trans *tp;
- xfs_fsblock_t firstfsb;
unsigned int resblks;
- struct xfs_defer_ops dfops;
struct xfs_bmbt_irec uirec;
xfs_filblks_t rlen;
xfs_filblks_t unmap_len;
@@ -1113,11 +1020,10 @@ xfs_reflink_remap_extent(
/* Unmap the old blocks in the data fork. */
rlen = unmap_len;
while (rlen) {
- xfs_defer_init(&dfops, &firstfsb);
- error = __xfs_bunmapi(tp, ip, destoff, &rlen, 0, 1,
- &firstfsb, &dfops);
+ ASSERT(tp->t_firstblock == NULLFSBLOCK);
+ error = __xfs_bunmapi(tp, ip, destoff, &rlen, 0, 1);
if (error)
- goto out_defer;
+ goto out_cancel;
/*
* Trim the extent to whatever got unmapped.
@@ -1136,14 +1042,14 @@ xfs_reflink_remap_extent(
uirec.br_blockcount, uirec.br_startblock);
/* Update the refcount tree */
- error = xfs_refcount_increase_extent(mp, &dfops, &uirec);
+ error = xfs_refcount_increase_extent(tp, &uirec);
if (error)
- goto out_defer;
+ goto out_cancel;
/* Map the new blocks into the data fork. */
- error = xfs_bmap_map_extent(mp, &dfops, ip, &uirec);
+ error = xfs_bmap_map_extent(tp, ip, &uirec);
if (error)
- goto out_defer;
+ goto out_cancel;
/* Update quota accounting. */
xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT,
@@ -1162,10 +1068,9 @@ xfs_reflink_remap_extent(
next_extent:
/* Process all the deferred stuff. */
- xfs_defer_ijoin(&dfops, ip);
- error = xfs_defer_finish(&tp, &dfops);
+ error = xfs_defer_finish(&tp);
if (error)
- goto out_defer;
+ goto out_cancel;
}
error = xfs_trans_commit(tp);
@@ -1174,8 +1079,6 @@ next_extent:
goto out;
return 0;
-out_defer:
- xfs_defer_cancel(&dfops);
out_cancel:
xfs_trans_cancel(tp);
xfs_iunlock(ip, XFS_ILOCK_EXCL);