xfs: remove xfs_reflink_dirty_extents

Now that xfs_file_unshare is not completely dumb we can just call it
directly without iterating the extent and reflink btrees ourselves.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
This commit is contained in:
Christoph Hellwig 2019-10-19 09:09:43 -07:00 committed by Darrick J. Wong
parent 0d45e3a208
commit dd26b84640
1 changed files with 5 additions and 98 deletions

View File

@ -1381,85 +1381,6 @@ xfs_reflink_remap_prep(
return ret;
}
/*
* The user wants to preemptively CoW all shared blocks in this file,
* which enables us to turn off the reflink flag. Iterate all
* extents which are not prealloc/delalloc to see which ranges are
* mentioned in the refcount tree, then read those blocks into the
* pagecache, dirty them, fsync them back out, and then we can update
* the inode flag. What happens if we run out of memory? :)
*/
STATIC int
xfs_reflink_dirty_extents(
struct xfs_inode *ip,
xfs_fileoff_t fbno,
xfs_filblks_t end,
xfs_off_t isize)
{
struct xfs_mount *mp = ip->i_mount;
xfs_agnumber_t agno;
xfs_agblock_t agbno;
xfs_extlen_t aglen;
xfs_agblock_t rbno;
xfs_extlen_t rlen;
xfs_off_t fpos;
xfs_off_t flen;
struct xfs_bmbt_irec map[2];
int nmaps;
int error = 0;
while (end - fbno > 0) {
nmaps = 1;
/*
* Look for extents in the file. Skip holes, delalloc, or
* unwritten extents; they can't be reflinked.
*/
error = xfs_bmapi_read(ip, fbno, end - fbno, map, &nmaps, 0);
if (error)
goto out;
if (nmaps == 0)
break;
if (!xfs_bmap_is_real_extent(&map[0]))
goto next;
map[1] = map[0];
while (map[1].br_blockcount) {
agno = XFS_FSB_TO_AGNO(mp, map[1].br_startblock);
agbno = XFS_FSB_TO_AGBNO(mp, map[1].br_startblock);
aglen = map[1].br_blockcount;
error = xfs_reflink_find_shared(mp, NULL, agno, agbno,
aglen, &rbno, &rlen, true);
if (error)
goto out;
if (rbno == NULLAGBLOCK)
break;
/* Dirty the pages */
xfs_iunlock(ip, XFS_ILOCK_EXCL);
fpos = XFS_FSB_TO_B(mp, map[1].br_startoff +
(rbno - agbno));
flen = XFS_FSB_TO_B(mp, rlen);
if (fpos + flen > isize)
flen = isize - fpos;
error = iomap_file_unshare(VFS_I(ip), fpos, flen,
&xfs_iomap_ops);
xfs_ilock(ip, XFS_ILOCK_EXCL);
if (error)
goto out;
map[1].br_blockcount -= (rbno - agbno + rlen);
map[1].br_startoff += (rbno - agbno + rlen);
map[1].br_startblock += (rbno - agbno + rlen);
}
next:
fbno = map[0].br_startoff + map[0].br_blockcount;
}
out:
return error;
}
/* Does this inode need the reflink flag? */
int
xfs_reflink_inode_has_shared_extents(
@ -1596,10 +1517,7 @@ xfs_reflink_unshare(
xfs_off_t offset,
xfs_off_t len)
{
struct xfs_mount *mp = ip->i_mount;
xfs_fileoff_t fbno;
xfs_filblks_t end;
xfs_off_t isize;
struct inode *inode = VFS_I(ip);
int error;
if (!xfs_is_reflink_inode(ip))
@ -1607,20 +1525,12 @@ xfs_reflink_unshare(
trace_xfs_reflink_unshare(ip, offset, len);
inode_dio_wait(VFS_I(ip));
inode_dio_wait(inode);
/* Try to CoW the selected ranges */
xfs_ilock(ip, XFS_ILOCK_EXCL);
fbno = XFS_B_TO_FSBT(mp, offset);
isize = i_size_read(VFS_I(ip));
end = XFS_B_TO_FSB(mp, offset + len);
error = xfs_reflink_dirty_extents(ip, fbno, end, isize);
error = iomap_file_unshare(inode, offset, len, &xfs_iomap_ops);
if (error)
goto out_unlock;
xfs_iunlock(ip, XFS_ILOCK_EXCL);
/* Wait for the IO to finish */
error = filemap_write_and_wait(VFS_I(ip)->i_mapping);
goto out;
error = filemap_write_and_wait(inode->i_mapping);
if (error)
goto out;
@ -1628,11 +1538,8 @@ xfs_reflink_unshare(
error = xfs_reflink_try_clear_inode_flag(ip);
if (error)
goto out;
return 0;
out_unlock:
xfs_iunlock(ip, XFS_ILOCK_EXCL);
out:
trace_xfs_reflink_unshare_error(ip, error, _RET_IP_);
return error;