|
@@ -282,23 +282,15 @@ xfs_inactive_symlink_rmt(
|
|
|
* free them all in one bunmapi call.
|
|
|
*/
|
|
|
ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2);
|
|
|
- if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
|
|
|
- XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) {
|
|
|
- ASSERT(XFS_FORCED_SHUTDOWN(mp));
|
|
|
- xfs_trans_cancel(tp, 0);
|
|
|
- *tpp = NULL;
|
|
|
- return error;
|
|
|
- }
|
|
|
+
|
|
|
/*
|
|
|
* Lock the inode, fix the size, and join it to the transaction.
|
|
|
* Hold it so in the normal path, we still have it locked for
|
|
|
* the second transaction. In the error paths we need it
|
|
|
* held so the cancel won't rele it, see below.
|
|
|
*/
|
|
|
- xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
|
|
|
size = (int)ip->i_d.di_size;
|
|
|
ip->i_d.di_size = 0;
|
|
|
- xfs_trans_ijoin(tp, ip, 0);
|
|
|
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
|
|
|
/*
|
|
|
* Find the block(s) so we can inval and unmap them.
|
|
@@ -385,67 +377,15 @@ xfs_inactive_symlink_rmt(
|
|
|
ASSERT(XFS_FORCED_SHUTDOWN(mp));
|
|
|
goto error0;
|
|
|
}
|
|
|
- /*
|
|
|
- * Return with the inode locked but not joined to the transaction.
|
|
|
- */
|
|
|
+
|
|
|
+ xfs_trans_ijoin(tp, ip, 0);
|
|
|
*tpp = tp;
|
|
|
return 0;
|
|
|
|
|
|
error1:
|
|
|
xfs_bmap_cancel(&free_list);
|
|
|
error0:
|
|
|
- /*
|
|
|
- * Have to come here with the inode locked and either
|
|
|
- * (held and in the transaction) or (not in the transaction).
|
|
|
- * If the inode isn't held then cancel would iput it, but
|
|
|
- * that's wrong since this is inactive and the vnode ref
|
|
|
- * count is 0 already.
|
|
|
- * Cancel won't do anything to the inode if held, but it still
|
|
|
- * needs to be locked until the cancel is done, if it was
|
|
|
- * joined to the transaction.
|
|
|
- */
|
|
|
- xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
|
|
|
- xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
|
|
|
- *tpp = NULL;
|
|
|
return error;
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-xfs_inactive_symlink_local(
|
|
|
- xfs_inode_t *ip,
|
|
|
- xfs_trans_t **tpp)
|
|
|
-{
|
|
|
- int error;
|
|
|
-
|
|
|
- ASSERT(ip->i_d.di_size <= XFS_IFORK_DSIZE(ip));
|
|
|
- /*
|
|
|
- * We're freeing a symlink which fit into
|
|
|
- * the inode. Just free the memory used
|
|
|
- * to hold the old symlink.
|
|
|
- */
|
|
|
- error = xfs_trans_reserve(*tpp, 0,
|
|
|
- XFS_ITRUNCATE_LOG_RES(ip->i_mount),
|
|
|
- 0, XFS_TRANS_PERM_LOG_RES,
|
|
|
- XFS_ITRUNCATE_LOG_COUNT);
|
|
|
-
|
|
|
- if (error) {
|
|
|
- xfs_trans_cancel(*tpp, 0);
|
|
|
- *tpp = NULL;
|
|
|
- return error;
|
|
|
- }
|
|
|
- xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
|
|
|
-
|
|
|
- /*
|
|
|
- * Zero length symlinks _can_ exist.
|
|
|
- */
|
|
|
- if (ip->i_df.if_bytes > 0) {
|
|
|
- xfs_idata_realloc(ip,
|
|
|
- -(ip->i_df.if_bytes),
|
|
|
- XFS_DATA_FORK);
|
|
|
- ASSERT(ip->i_df.if_bytes == 0);
|
|
|
- }
|
|
|
- return 0;
|
|
|
}
|
|
|
|
|
|
STATIC int
|
|
@@ -604,7 +544,7 @@ xfs_inactive(
|
|
|
xfs_trans_t *tp;
|
|
|
xfs_mount_t *mp;
|
|
|
int error;
|
|
|
- int truncate;
|
|
|
+ int truncate = 0;
|
|
|
|
|
|
/*
|
|
|
* If the inode is already free, then there can be nothing
|
|
@@ -616,17 +556,6 @@ xfs_inactive(
|
|
|
return VN_INACTIVE_CACHE;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * Only do a truncate if it's a regular file with
|
|
|
- * some actual space in it. It's OK to look at the
|
|
|
- * inode's fields without the lock because we're the
|
|
|
- * only one with a reference to the inode.
|
|
|
- */
|
|
|
- truncate = ((ip->i_d.di_nlink == 0) &&
|
|
|
- ((ip->i_d.di_size != 0) || XFS_ISIZE(ip) != 0 ||
|
|
|
- (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) &&
|
|
|
- S_ISREG(ip->i_d.di_mode));
|
|
|
-
|
|
|
mp = ip->i_mount;
|
|
|
|
|
|
error = 0;
|
|
@@ -650,72 +579,54 @@ xfs_inactive(
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ASSERT(ip->i_d.di_nlink == 0);
|
|
|
+ if (S_ISREG(ip->i_d.di_mode) &&
|
|
|
+ (ip->i_d.di_size != 0 || XFS_ISIZE(ip) != 0 ||
|
|
|
+ ip->i_d.di_nextents > 0 || ip->i_delayed_blks > 0))
|
|
|
+ truncate = 1;
|
|
|
|
|
|
error = xfs_qm_dqattach(ip, 0);
|
|
|
if (error)
|
|
|
return VN_INACTIVE_CACHE;
|
|
|
|
|
|
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
|
|
|
- if (truncate) {
|
|
|
- xfs_ilock(ip, XFS_IOLOCK_EXCL);
|
|
|
-
|
|
|
- error = xfs_trans_reserve(tp, 0,
|
|
|
- XFS_ITRUNCATE_LOG_RES(mp),
|
|
|
- 0, XFS_TRANS_PERM_LOG_RES,
|
|
|
- XFS_ITRUNCATE_LOG_COUNT);
|
|
|
- if (error) {
|
|
|
- /* Don't call itruncate_cleanup */
|
|
|
- ASSERT(XFS_FORCED_SHUTDOWN(mp));
|
|
|
- xfs_trans_cancel(tp, 0);
|
|
|
- xfs_iunlock(ip, XFS_IOLOCK_EXCL);
|
|
|
- return VN_INACTIVE_CACHE;
|
|
|
- }
|
|
|
+ error = xfs_trans_reserve(tp, 0,
|
|
|
+ (truncate || S_ISLNK(ip->i_d.di_mode)) ?
|
|
|
+ XFS_ITRUNCATE_LOG_RES(mp) :
|
|
|
+ XFS_IFREE_LOG_RES(mp),
|
|
|
+ 0,
|
|
|
+ XFS_TRANS_PERM_LOG_RES,
|
|
|
+ XFS_ITRUNCATE_LOG_COUNT);
|
|
|
+ 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);
|
|
|
+ xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
|
|
|
+ xfs_trans_ijoin(tp, ip, 0);
|
|
|
|
|
|
+ if (S_ISLNK(ip->i_d.di_mode)) {
|
|
|
+ /*
|
|
|
+ * Zero length symlinks _can_ exist.
|
|
|
+ */
|
|
|
+ if (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) {
|
|
|
+ error = xfs_inactive_symlink_rmt(ip, &tp);
|
|
|
+ if (error)
|
|
|
+ goto out_cancel;
|
|
|
+ } else if (ip->i_df.if_bytes > 0) {
|
|
|
+ xfs_idata_realloc(ip, -(ip->i_df.if_bytes),
|
|
|
+ XFS_DATA_FORK);
|
|
|
+ ASSERT(ip->i_df.if_bytes == 0);
|
|
|
+ }
|
|
|
+ } 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) {
|
|
|
- xfs_trans_cancel(tp,
|
|
|
- XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
|
|
|
- xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
|
|
|
- return VN_INACTIVE_CACHE;
|
|
|
- }
|
|
|
+ if (error)
|
|
|
+ goto out_cancel;
|
|
|
|
|
|
ASSERT(ip->i_d.di_nextents == 0);
|
|
|
- } else if (S_ISLNK(ip->i_d.di_mode)) {
|
|
|
-
|
|
|
- /*
|
|
|
- * If we get an error while cleaning up a
|
|
|
- * symlink we bail out.
|
|
|
- */
|
|
|
- error = (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) ?
|
|
|
- xfs_inactive_symlink_rmt(ip, &tp) :
|
|
|
- xfs_inactive_symlink_local(ip, &tp);
|
|
|
-
|
|
|
- if (error) {
|
|
|
- ASSERT(tp == NULL);
|
|
|
- return VN_INACTIVE_CACHE;
|
|
|
- }
|
|
|
-
|
|
|
- xfs_trans_ijoin(tp, ip, 0);
|
|
|
- } else {
|
|
|
- error = xfs_trans_reserve(tp, 0,
|
|
|
- XFS_IFREE_LOG_RES(mp),
|
|
|
- 0, XFS_TRANS_PERM_LOG_RES,
|
|
|
- XFS_INACTIVE_LOG_COUNT);
|
|
|
- if (error) {
|
|
|
- ASSERT(XFS_FORCED_SHUTDOWN(mp));
|
|
|
- xfs_trans_cancel(tp, 0);
|
|
|
- return VN_INACTIVE_CACHE;
|
|
|
- }
|
|
|
-
|
|
|
- xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
|
|
|
- xfs_trans_ijoin(tp, ip, 0);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -781,7 +692,11 @@ xfs_inactive(
|
|
|
xfs_qm_dqdetach(ip);
|
|
|
xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
|
|
|
|
|
|
- out:
|
|
|
+out:
|
|
|
+ return VN_INACTIVE_CACHE;
|
|
|
+out_cancel:
|
|
|
+ xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
|
|
|
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
|
|
|
return VN_INACTIVE_CACHE;
|
|
|
}
|
|
|
|