return error;
  }
  
 +/*
 + * xfs_attr_inactive kills all traces of an attribute fork on an inode. It
 + * removes both the on-disk and in-memory inode fork. Note that this also has to
 + * handle the condition of inodes without attributes but with an attribute fork
 + * configured, so we can't use xfs_inode_hasattr() here.
 + *
 + * The in-memory attribute fork is removed even on error.
 + */
  int
 -xfs_attr_inactive(xfs_inode_t *dp)
 +xfs_attr_inactive(
 +      struct xfs_inode        *dp)
  {
 -      xfs_trans_t *trans;
 -      xfs_mount_t *mp;
 -      int error;
 +      struct xfs_trans        *trans;
 +      struct xfs_mount        *mp;
-       int                     cancel_flags = 0;
 +      int                     lock_mode = XFS_ILOCK_SHARED;
 +      int                     error = 0;
  
        mp = dp->i_mount;
        ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
         * the inode in every transaction to let it float upward through
         * the log.
         */
 +      lock_mode = 0;
        trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL);
        error = xfs_trans_reserve(trans, &M_RES(mp)->tr_attrinval, 0, 0);
 -      if (error) {
 -              xfs_trans_cancel(trans);
 -              return error;
 -      }
 -      xfs_ilock(dp, XFS_ILOCK_EXCL);
 +      if (error)
 +              goto out_cancel;
 +
 +      lock_mode = XFS_ILOCK_EXCL;
-       cancel_flags = XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT;
 +      xfs_ilock(dp, lock_mode);
 +
 +      if (!XFS_IFORK_Q(dp))
 +              goto out_cancel;
  
        /*
         * No need to make quota reservations here. We expect to release some
         */
        xfs_trans_ijoin(trans, dp, 0);
  
 -      /*
 -       * Decide on what work routines to call based on the inode size.
 -       */
 -      if (!xfs_inode_hasattr(dp) ||
 -          dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
 -              error = 0;
 -              goto out;
 +      /* invalidate and truncate the attribute fork extents */
 +      if (dp->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) {
 +              error = xfs_attr3_root_inactive(&trans, dp);
 +              if (error)
 +                      goto out_cancel;
 +
 +              error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0);
 +              if (error)
 +                      goto out_cancel;
        }
 -      error = xfs_attr3_root_inactive(&trans, dp);
 -      if (error)
 -              goto out;
  
 -      error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0);
 -      if (error)
 -              goto out;
 +      /* Reset the attribute fork - this also destroys the in-core fork */
 +      xfs_attr_fork_remove(dp, trans);
  
-       error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES);
+       error = xfs_trans_commit(trans);
 -      xfs_iunlock(dp, XFS_ILOCK_EXCL);
 -
 +      xfs_iunlock(dp, lock_mode);
        return error;
  
 -out:
 +out_cancel:
-       xfs_trans_cancel(trans, cancel_flags);
+       xfs_trans_cancel(trans);
 -      xfs_iunlock(dp, XFS_ILOCK_EXCL);
 +out_destroy_fork:
 +      /* kill the in-core attr fork before we drop the inode lock */
 +      if (dp->i_afp)
 +              xfs_idestroy_fork(dp, XFS_ATTR_FORK);
 +      if (lock_mode)
 +              xfs_iunlock(dp, lock_mode);
        return error;
  }