[RFC PATCH 06/11] xfs: use correct transaction reservations in xfs_inactive()

Brian Foster
2013-09-03T18:25:49Z

The transaction allocated in xfs_inactive() can be passed down into
xfs_inactive_symlink() or xfs_itruncate_extents(), both of which
can commit and reallocate a new transaction. This leads to
reservation issues if the transaction is subsequently passed into
xfs_ifree(), which requires a larger reservation to manage the
finobt.

Reorganize xfs_inactive() to commit any transaction handed back
from symlink or truncate processing and unconditionally allocate
a new transaction for xfs_ifree() with the appropriate reservation.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
fs/xfs/xfs_inode.c | 71 ++++++++++++++++++++++++++++--------------------------
1 file changed, 37 insertions(+), 34 deletions(-)

diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index e3d7538..56cbf63 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1679,7 +1679,6 @@ xfs_inactive(
int committed;
struct xfs_trans *tp;
struct xfs_mount *mp;
- struct xfs_trans_res *resp;
int error;
int truncate = 0;

@@ -1724,33 +1723,39 @@ xfs_inactive(
if (error)
return VN_INACTIVE_CACHE;

- tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
- resp = (truncate || S_ISLNK(ip->i_d.di_mode)) ?
- &M_RES(mp)->tr_itruncate : &M_RES(mp)->tr_ifree;
+ xfs_ilock(ip, XFS_ILOCK_EXCL);

- error = xfs_trans_reserve(tp, resp, 0, 0);
- if (error) {
- ASSERT(XFS_FORCED_SHUTDOWN(mp));
- xfs_trans_cancel(tp, 0);
- return VN_INACTIVE_CACHE;
- }
+ if (truncate || S_ISLNK(ip->i_d.di_mode)) {
+ tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);

- xfs_ilock(ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip, 0);
+ 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 VN_INACTIVE_CACHE;
+ }

- if (S_ISLNK(ip->i_d.di_mode)) {
- error = xfs_inactive_symlink(ip, &tp);
- if (error)
- goto out_cancel;
- } else if (truncate) {
- ip->i_d.di_size = 0;
- xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+ xfs_trans_ijoin(tp, ip, 0);
+
+ if (S_ISLNK(ip->i_d.di_mode)) {
+ error = xfs_inactive_symlink(ip, &tp);
+ if (error)
+ goto out_cancel;
+ } else 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;

- error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
+ ASSERT(ip->i_d.di_nextents == 0);
+ }
+
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error)
goto out_cancel;
-
- ASSERT(ip->i_d.di_nextents == 0);
}

/*
@@ -1762,27 +1767,25 @@ 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);
}

+ tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
+ error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree,
+ XFS_IFREE_SPACE_RES(mp), 0);
+ if (error) {
+ xfs_trans_cancel(tp, 0);
+ goto out_unlock;
+ }
+
+ xfs_trans_ijoin(tp, ip, 0);
+
if (ip->i_afp)
xfs_idestroy_fork(ip, XFS_ATTR_FORK);

--
1.8.1.4