On Tue, Oct 08, 2019 at 09:15:17AM +0200, Christoph Hellwig wrote: > 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@xxxxxx> Looks ok, Reviewed-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> --D > --- > fs/xfs/xfs_reflink.c | 103 +++---------------------------------------- > 1 file changed, 5 insertions(+), 98 deletions(-) > > diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c > index a9634110c783..7fc728a8852b 100644 > --- a/fs/xfs/xfs_reflink.c > +++ b/fs/xfs/xfs_reflink.c > @@ -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; > -- > 2.20.1 >