diff options
Diffstat (limited to 'fs/xfs/xfs_bmap_util.c')
-rw-r--r-- | fs/xfs/xfs_bmap_util.c | 149 |
1 files changed, 15 insertions, 134 deletions
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index 240b540e172f..4ca2688ab14e 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c @@ -1350,135 +1350,6 @@ xfs_swap_extent_flush( return 0; } -/* - * Move extents from one file to another, when rmap is enabled. - */ -STATIC int -xfs_swap_extent_rmap( - struct xfs_trans **tpp, - struct xfs_inode *ip, - struct xfs_inode *tip) -{ - struct xfs_trans *tp = *tpp; - struct xfs_bmbt_irec irec; - struct xfs_bmbt_irec uirec; - struct xfs_bmbt_irec tirec; - xfs_fileoff_t offset_fsb; - xfs_fileoff_t end_fsb; - xfs_filblks_t count_fsb; - int error; - xfs_filblks_t ilen; - xfs_filblks_t rlen; - int nimaps; - uint64_t tip_flags2; - - /* - * If the source file has shared blocks, we must flag the donor - * file as having shared blocks so that we get the shared-block - * rmap functions when we go to fix up the rmaps. The flags - * will be switch for reals later. - */ - tip_flags2 = tip->i_d.di_flags2; - if (ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK) - tip->i_d.di_flags2 |= XFS_DIFLAG2_REFLINK; - - offset_fsb = 0; - end_fsb = XFS_B_TO_FSB(ip->i_mount, i_size_read(VFS_I(ip))); - count_fsb = (xfs_filblks_t)(end_fsb - offset_fsb); - - while (count_fsb) { - /* Read extent from the donor file */ - nimaps = 1; - error = xfs_bmapi_read(tip, offset_fsb, count_fsb, &tirec, - &nimaps, 0); - if (error) - goto out; - ASSERT(nimaps == 1); - ASSERT(tirec.br_startblock != DELAYSTARTBLOCK); - - trace_xfs_swap_extent_rmap_remap(tip, &tirec); - ilen = tirec.br_blockcount; - - /* Unmap the old blocks in the source file. */ - while (tirec.br_blockcount) { - int64_t ip_delta = 0, tip_delta = 0; - - ASSERT(tp->t_firstblock == NULLFSBLOCK); - trace_xfs_swap_extent_rmap_remap_piece(tip, &tirec); - - /* Read extent from the source file */ - nimaps = 1; - error = xfs_bmapi_read(ip, tirec.br_startoff, - tirec.br_blockcount, &irec, - &nimaps, 0); - if (error) - goto out; - ASSERT(nimaps == 1); - ASSERT(tirec.br_startoff == irec.br_startoff); - trace_xfs_swap_extent_rmap_remap_piece(ip, &irec); - - /* Trim the extent. */ - uirec = tirec; - uirec.br_blockcount = rlen = min_t(xfs_filblks_t, - tirec.br_blockcount, - irec.br_blockcount); - trace_xfs_swap_extent_rmap_remap_piece(tip, &uirec); - - /* Update quota accounting. */ - if (xfs_bmap_is_mapped_extent(&irec)) { - tip_delta += irec.br_blockcount; - ip_delta -= irec.br_blockcount; - } - if (xfs_bmap_is_mapped_extent(&uirec)) { - tip_delta -= uirec.br_blockcount; - ip_delta += uirec.br_blockcount; - } - - if (tip_delta) - xfs_trans_mod_dquot_byino(tp, tip, - XFS_TRANS_DQ_BCOUNT, tip_delta); - if (ip_delta) - xfs_trans_mod_dquot_byino(tp, ip, - XFS_TRANS_DQ_BCOUNT, ip_delta); - - /* Remove the mapping from the donor file. */ - xfs_bmap_unmap_extent(tp, tip, XFS_DATA_FORK, &uirec); - - /* Remove the mapping from the source file. */ - xfs_bmap_unmap_extent(tp, ip, XFS_DATA_FORK, &irec); - - /* Map the donor file's blocks into the source file. */ - xfs_bmap_map_extent(tp, ip, XFS_DATA_FORK, &uirec); - - /* Map the source file's blocks into the donor file. */ - xfs_bmap_map_extent(tp, tip, XFS_DATA_FORK, &irec); - - error = xfs_defer_finish(tpp); - tp = *tpp; - if (error) - goto out; - - tirec.br_startoff += rlen; - if (tirec.br_startblock != HOLESTARTBLOCK && - tirec.br_startblock != DELAYSTARTBLOCK) - tirec.br_startblock += rlen; - tirec.br_blockcount -= rlen; - } - - /* Roll on... */ - count_fsb -= ilen; - offset_fsb += ilen; - } - - tip->i_d.di_flags2 = tip_flags2; - return 0; - -out: - trace_xfs_swap_extent_rmap_error(ip, error, _RET_IP_); - tip->i_d.di_flags2 = tip_flags2; - return error; -} - /* Swap the extents of two files by swapping data forks. */ STATIC int xfs_swap_extent_forks( @@ -1873,16 +1744,26 @@ xfs_swap_extents( src_log_flags = XFS_ILOG_CORE; target_log_flags = XFS_ILOG_CORE; - if (xfs_sb_version_hasrmapbt(&mp->m_sb)) - error = xfs_swap_extent_rmap(&tp, ip, tip); - else + if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { + struct xfs_swapext_req req = { + .ip1 = ip, + .ip2 = tip, + .whichfork = XFS_DATA_FORK, + .blockcount = XFS_B_TO_FSB(ip->i_mount, + i_size_read(VFS_I(ip))), + }; + error = xfs_swapext_deferred_bmap(&tp, &req); + } else error = xfs_swap_extent_forks(tp, ip, tip, &src_log_flags, &target_log_flags); - if (error) + if (error) { + trace_xfs_swap_extent_error(ip, error, _THIS_IP_); goto out_trans_cancel; + } /* Do we have to swap reflink flags? */ - if ((ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK) ^ + if (!xfs_sb_version_hasrmapbt(&mp->m_sb) && + (ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK) ^ (tip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK)) { f = ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK; ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; |