xfs: push down inactive transaction mgmt for truncate

Create the new xfs_inactive_truncate() function to handle the
truncate portion of xfs_inactive(). Push the locking and
transaction management into the new function.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
This commit is contained in:
Brian Foster 2013-09-20 11:06:10 -04:00 committed by Ben Myers
parent 36b21dde6e
commit f7be2d7f59
1 changed files with 68 additions and 49 deletions

View File

@ -1662,6 +1662,58 @@ xfs_release(
return 0;
}
/*
* xfs_inactive_truncate
*
* Called to perform a truncate when an inode becomes unlinked.
*/
STATIC int
xfs_inactive_truncate(
struct xfs_inode *ip)
{
struct xfs_mount *mp = ip->i_mount;
struct xfs_trans *tp;
int error;
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
if (error) {
ASSERT(XFS_FORCED_SHUTDOWN(mp));
xfs_trans_cancel(tp, 0);
return error;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, 0);
/*
* Log the inode size first to prevent stale data exposure in the event
* of a system crash before the truncate completes. See the related
* comment in xfs_setattr_size() for details.
*/
ip->i_d.di_size = 0;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
if (error)
goto error_trans_cancel;
ASSERT(ip->i_d.di_nextents == 0);
error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error)
goto error_unlock;
xfs_iunlock(ip, XFS_ILOCK_EXCL);
return 0;
error_trans_cancel:
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
error_unlock:
xfs_iunlock(ip, XFS_ILOCK_EXCL);
return error;
}
/*
* xfs_inactive
*
@ -1679,7 +1731,6 @@ xfs_inactive(
int committed;
struct xfs_trans *tp;
struct xfs_mount *mp;
struct xfs_trans_res *resp;
int error;
int truncate = 0;
@ -1724,35 +1775,12 @@ xfs_inactive(
if (error)
return VN_INACTIVE_CACHE;
if (S_ISLNK(ip->i_d.di_mode)) {
if (S_ISLNK(ip->i_d.di_mode))
error = xfs_inactive_symlink(ip);
if (error)
goto out;
}
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
resp = truncate ? &M_RES(mp)->tr_itruncate : &M_RES(mp)->tr_ifree;
error = xfs_trans_reserve(tp, resp, 0, 0);
if (error) {
ASSERT(XFS_FORCED_SHUTDOWN(mp));
xfs_trans_cancel(tp, 0);
return VN_INACTIVE_CACHE;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, 0);
if (truncate) {
ip->i_d.di_size = 0;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
if (error)
goto out_cancel;
ASSERT(ip->i_d.di_nextents == 0);
}
else if (truncate)
error = xfs_inactive_truncate(ip);
if (error)
goto out;
/*
* If there are attributes associated with the file then blow them away
@ -1763,25 +1791,9 @@ xfs_inactive(
if (ip->i_d.di_anextents > 0) {
ASSERT(ip->i_d.di_forkoff != 0);
error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error)
goto out_unlock;
xfs_iunlock(ip, XFS_ILOCK_EXCL);
error = xfs_attr_inactive(ip);
if (error)
goto out;
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree, 0, 0);
if (error) {
xfs_trans_cancel(tp, 0);
goto out;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, 0);
}
if (ip->i_afp)
@ -1789,6 +1801,17 @@ xfs_inactive(
ASSERT(ip->i_d.di_anextents == 0);
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree, 0, 0);
if (error) {
ASSERT(XFS_FORCED_SHUTDOWN(mp));
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES);
goto out;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, 0);
/*
* Free the inode.
*/
@ -1831,13 +1854,9 @@ xfs_inactive(
* Release the dquots held by inode, if any.
*/
xfs_qm_dqdetach(ip);
out_unlock:
xfs_iunlock(ip, XFS_ILOCK_EXCL);
out:
return VN_INACTIVE_CACHE;
out_cancel:
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
goto out_unlock;
}
/*