forked from Minki/linux
xfs: split xfs_free_file_space in manageable pieces
Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
parent
570b6211b8
commit
bdb0d04fa6
@ -1184,30 +1184,132 @@ xfs_zero_remaining_bytes(
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_unmap_extent(
|
||||
struct xfs_inode *ip,
|
||||
xfs_fileoff_t startoffset_fsb,
|
||||
xfs_filblks_t len_fsb,
|
||||
int *done)
|
||||
{
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
struct xfs_trans *tp;
|
||||
struct xfs_bmap_free free_list;
|
||||
xfs_fsblock_t firstfsb;
|
||||
uint resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
|
||||
int error;
|
||||
|
||||
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp);
|
||||
if (error) {
|
||||
ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp));
|
||||
return error;
|
||||
}
|
||||
|
||||
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
||||
error = xfs_trans_reserve_quota(tp, mp, ip->i_udquot, ip->i_gdquot,
|
||||
ip->i_pdquot, resblks, 0, XFS_QMOPT_RES_REGBLKS);
|
||||
if (error)
|
||||
goto out_trans_cancel;
|
||||
|
||||
xfs_trans_ijoin(tp, ip, 0);
|
||||
|
||||
xfs_bmap_init(&free_list, &firstfsb);
|
||||
error = xfs_bunmapi(tp, ip, startoffset_fsb, len_fsb, 0, 2, &firstfsb,
|
||||
&free_list, done);
|
||||
if (error)
|
||||
goto out_bmap_cancel;
|
||||
|
||||
error = xfs_bmap_finish(&tp, &free_list, NULL);
|
||||
if (error)
|
||||
goto out_bmap_cancel;
|
||||
|
||||
error = xfs_trans_commit(tp);
|
||||
out_unlock:
|
||||
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
||||
return error;
|
||||
|
||||
out_bmap_cancel:
|
||||
xfs_bmap_cancel(&free_list);
|
||||
out_trans_cancel:
|
||||
xfs_trans_cancel(tp);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_adjust_extent_unmap_boundaries(
|
||||
struct xfs_inode *ip,
|
||||
xfs_fileoff_t *startoffset_fsb,
|
||||
xfs_fileoff_t *endoffset_fsb)
|
||||
{
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
struct xfs_bmbt_irec imap;
|
||||
int nimap, error;
|
||||
xfs_extlen_t mod = 0;
|
||||
|
||||
nimap = 1;
|
||||
error = xfs_bmapi_read(ip, *startoffset_fsb, 1, &imap, &nimap, 0);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
|
||||
xfs_daddr_t block;
|
||||
|
||||
ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
|
||||
block = imap.br_startblock;
|
||||
mod = do_div(block, mp->m_sb.sb_rextsize);
|
||||
if (mod)
|
||||
*startoffset_fsb += mp->m_sb.sb_rextsize - mod;
|
||||
}
|
||||
|
||||
nimap = 1;
|
||||
error = xfs_bmapi_read(ip, *endoffset_fsb - 1, 1, &imap, &nimap, 0);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
|
||||
ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
|
||||
mod++;
|
||||
if (mod && mod != mp->m_sb.sb_rextsize)
|
||||
*endoffset_fsb -= mod;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_flush_unmap_range(
|
||||
struct xfs_inode *ip,
|
||||
xfs_off_t offset,
|
||||
xfs_off_t len)
|
||||
{
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
struct inode *inode = VFS_I(ip);
|
||||
xfs_off_t rounding, start, end;
|
||||
int error;
|
||||
|
||||
/* wait for the completion of any pending DIOs */
|
||||
inode_dio_wait(inode);
|
||||
|
||||
rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_SIZE);
|
||||
start = round_down(offset, rounding);
|
||||
end = round_up(offset + len, rounding) - 1;
|
||||
|
||||
error = filemap_write_and_wait_range(inode->i_mapping, start, end);
|
||||
if (error)
|
||||
return error;
|
||||
truncate_pagecache_range(inode, start, end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_free_file_space(
|
||||
struct xfs_inode *ip,
|
||||
xfs_off_t offset,
|
||||
xfs_off_t len)
|
||||
{
|
||||
int done;
|
||||
xfs_fileoff_t endoffset_fsb;
|
||||
int error;
|
||||
xfs_fsblock_t firstfsb;
|
||||
xfs_bmap_free_t free_list;
|
||||
xfs_bmbt_irec_t imap;
|
||||
xfs_off_t ioffset;
|
||||
xfs_off_t iendoffset;
|
||||
xfs_extlen_t mod=0;
|
||||
xfs_mount_t *mp;
|
||||
int nimap;
|
||||
uint resblks;
|
||||
xfs_off_t rounding;
|
||||
int rt;
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
xfs_fileoff_t startoffset_fsb;
|
||||
xfs_trans_t *tp;
|
||||
|
||||
mp = ip->i_mount;
|
||||
xfs_fileoff_t endoffset_fsb;
|
||||
int done, error;
|
||||
|
||||
trace_xfs_free_file_space(ip);
|
||||
|
||||
@ -1215,60 +1317,30 @@ xfs_free_file_space(
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = 0;
|
||||
if (len <= 0) /* if nothing being freed */
|
||||
return 0;
|
||||
|
||||
error = xfs_flush_unmap_range(ip, offset, len);
|
||||
if (error)
|
||||
return error;
|
||||
rt = XFS_IS_REALTIME_INODE(ip);
|
||||
startoffset_fsb = XFS_B_TO_FSB(mp, offset);
|
||||
|
||||
startoffset_fsb = XFS_B_TO_FSB(mp, offset);
|
||||
endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);
|
||||
|
||||
/* wait for the completion of any pending DIOs */
|
||||
inode_dio_wait(VFS_I(ip));
|
||||
|
||||
rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_SIZE);
|
||||
ioffset = round_down(offset, rounding);
|
||||
iendoffset = round_up(offset + len, rounding) - 1;
|
||||
error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, ioffset,
|
||||
iendoffset);
|
||||
if (error)
|
||||
goto out;
|
||||
truncate_pagecache_range(VFS_I(ip), ioffset, iendoffset);
|
||||
|
||||
/*
|
||||
* Need to zero the stuff we're not freeing, on disk.
|
||||
* If it's a realtime file & can't use unwritten extents then we
|
||||
* actually need to zero the extent edges. Otherwise xfs_bunmapi
|
||||
* will take care of it for us.
|
||||
* Need to zero the stuff we're not freeing, on disk. If it's a RT file
|
||||
* and we can't use unwritten extents then we actually need to ensure
|
||||
* to zero the whole extent, otherwise we just need to take of block
|
||||
* boundaries, and xfs_bunmapi will handle the rest.
|
||||
*/
|
||||
if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) {
|
||||
nimap = 1;
|
||||
error = xfs_bmapi_read(ip, startoffset_fsb, 1,
|
||||
&imap, &nimap, 0);
|
||||
if (XFS_IS_REALTIME_INODE(ip) &&
|
||||
!xfs_sb_version_hasextflgbit(&mp->m_sb)) {
|
||||
error = xfs_adjust_extent_unmap_boundaries(ip, &startoffset_fsb,
|
||||
&endoffset_fsb);
|
||||
if (error)
|
||||
goto out;
|
||||
ASSERT(nimap == 0 || nimap == 1);
|
||||
if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
|
||||
xfs_daddr_t block;
|
||||
|
||||
ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
|
||||
block = imap.br_startblock;
|
||||
mod = do_div(block, mp->m_sb.sb_rextsize);
|
||||
if (mod)
|
||||
startoffset_fsb += mp->m_sb.sb_rextsize - mod;
|
||||
}
|
||||
nimap = 1;
|
||||
error = xfs_bmapi_read(ip, endoffset_fsb - 1, 1,
|
||||
&imap, &nimap, 0);
|
||||
if (error)
|
||||
goto out;
|
||||
ASSERT(nimap == 0 || nimap == 1);
|
||||
if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
|
||||
ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
|
||||
mod++;
|
||||
if (mod && (mod != mp->m_sb.sb_rextsize))
|
||||
endoffset_fsb -= mod;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
if ((done = (endoffset_fsb <= startoffset_fsb)))
|
||||
/*
|
||||
* One contiguous piece to clear
|
||||
@ -1288,62 +1360,12 @@ xfs_free_file_space(
|
||||
offset + len - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* free file space until done or until there is an error
|
||||
*/
|
||||
resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
|
||||
while (!error && !done) {
|
||||
|
||||
/*
|
||||
* allocate and setup the transaction. Allow this
|
||||
* transaction to dip into the reserve blocks to ensure
|
||||
* the freeing of the space succeeds at ENOSPC.
|
||||
*/
|
||||
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0,
|
||||
&tp);
|
||||
if (error) {
|
||||
ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp));
|
||||
break;
|
||||
}
|
||||
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
||||
error = xfs_trans_reserve_quota(tp, mp,
|
||||
ip->i_udquot, ip->i_gdquot, ip->i_pdquot,
|
||||
resblks, 0, XFS_QMOPT_RES_REGBLKS);
|
||||
if (error)
|
||||
goto error1;
|
||||
|
||||
xfs_trans_ijoin(tp, ip, 0);
|
||||
|
||||
/*
|
||||
* issue the bunmapi() call to free the blocks
|
||||
*/
|
||||
xfs_bmap_init(&free_list, &firstfsb);
|
||||
error = xfs_bunmapi(tp, ip, startoffset_fsb,
|
||||
endoffset_fsb - startoffset_fsb,
|
||||
0, 2, &firstfsb, &free_list, &done);
|
||||
if (error)
|
||||
goto error0;
|
||||
|
||||
/*
|
||||
* complete the transaction
|
||||
*/
|
||||
error = xfs_bmap_finish(&tp, &free_list, NULL);
|
||||
if (error)
|
||||
goto error0;
|
||||
|
||||
error = xfs_trans_commit(tp);
|
||||
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
||||
error = xfs_unmap_extent(ip, startoffset_fsb,
|
||||
endoffset_fsb - startoffset_fsb, &done);
|
||||
}
|
||||
|
||||
out:
|
||||
return error;
|
||||
|
||||
error0:
|
||||
xfs_bmap_cancel(&free_list);
|
||||
error1:
|
||||
xfs_trans_cancel(tp);
|
||||
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user