xfs: kill xfs_itruncate_start
[linux-2.6.git] / fs / xfs / xfs_vnodeops.c
index b7bdc43..45b8ac6 100644 (file)
 #include "xfs_vnodeops.h"
 #include "xfs_trace.h"
 
-int
-xfs_setattr(
-       struct xfs_inode        *ip,
-       struct iattr            *iattr,
-       int                     flags)
-{
-       xfs_mount_t             *mp = ip->i_mount;
-       struct inode            *inode = VFS_I(ip);
-       int                     mask = iattr->ia_valid;
-       xfs_trans_t             *tp;
-       int                     code;
-       uint                    lock_flags;
-       uint                    commit_flags=0;
-       uid_t                   uid=0, iuid=0;
-       gid_t                   gid=0, igid=0;
-       struct xfs_dquot        *udqp, *gdqp, *olddquot1, *olddquot2;
-       int                     need_iolock = 1;
-
-       trace_xfs_setattr(ip);
-
-       if (mp->m_flags & XFS_MOUNT_RDONLY)
-               return XFS_ERROR(EROFS);
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
-
-       code = -inode_change_ok(inode, iattr);
-       if (code)
-               return code;
-
-       olddquot1 = olddquot2 = NULL;
-       udqp = gdqp = NULL;
-
-       /*
-        * If disk quotas is on, we make sure that the dquots do exist on disk,
-        * before we start any other transactions. Trying to do this later
-        * is messy. We don't care to take a readlock to look at the ids
-        * in inode here, because we can't hold it across the trans_reserve.
-        * If the IDs do change before we take the ilock, we're covered
-        * because the i_*dquot fields will get updated anyway.
-        */
-       if (XFS_IS_QUOTA_ON(mp) && (mask & (ATTR_UID|ATTR_GID))) {
-               uint    qflags = 0;
-
-               if ((mask & ATTR_UID) && XFS_IS_UQUOTA_ON(mp)) {
-                       uid = iattr->ia_uid;
-                       qflags |= XFS_QMOPT_UQUOTA;
-               } else {
-                       uid = ip->i_d.di_uid;
-               }
-               if ((mask & ATTR_GID) && XFS_IS_GQUOTA_ON(mp)) {
-                       gid = iattr->ia_gid;
-                       qflags |= XFS_QMOPT_GQUOTA;
-               }  else {
-                       gid = ip->i_d.di_gid;
-               }
-
-               /*
-                * We take a reference when we initialize udqp and gdqp,
-                * so it is important that we never blindly double trip on
-                * the same variable. See xfs_create() for an example.
-                */
-               ASSERT(udqp == NULL);
-               ASSERT(gdqp == NULL);
-               code = xfs_qm_vop_dqalloc(ip, uid, gid, ip->i_d.di_projid,
-                                        qflags, &udqp, &gdqp);
-               if (code)
-                       return code;
-       }
-
-       /*
-        * For the other attributes, we acquire the inode lock and
-        * first do an error checking pass.
-        */
-       tp = NULL;
-       lock_flags = XFS_ILOCK_EXCL;
-       if (flags & XFS_ATTR_NOLOCK)
-               need_iolock = 0;
-       if (!(mask & ATTR_SIZE)) {
-               tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
-               commit_flags = 0;
-               code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp),
-                                        0, 0, 0);
-               if (code) {
-                       lock_flags = 0;
-                       goto error_return;
-               }
-       } else {
-               if (need_iolock)
-                       lock_flags |= XFS_IOLOCK_EXCL;
-       }
-
-       xfs_ilock(ip, lock_flags);
-
-       /*
-        * Change file ownership.  Must be the owner or privileged.
-        */
-       if (mask & (ATTR_UID|ATTR_GID)) {
-               /*
-                * These IDs could have changed since we last looked at them.
-                * But, we're assured that if the ownership did change
-                * while we didn't have the inode locked, inode's dquot(s)
-                * would have changed also.
-                */
-               iuid = ip->i_d.di_uid;
-               igid = ip->i_d.di_gid;
-               gid = (mask & ATTR_GID) ? iattr->ia_gid : igid;
-               uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid;
-
-               /*
-                * Do a quota reservation only if uid/gid is actually
-                * going to change.
-                */
-               if (XFS_IS_QUOTA_RUNNING(mp) &&
-                   ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
-                    (XFS_IS_GQUOTA_ON(mp) && igid != gid))) {
-                       ASSERT(tp);
-                       code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
-                                               capable(CAP_FOWNER) ?
-                                               XFS_QMOPT_FORCE_RES : 0);
-                       if (code)       /* out of quota */
-                               goto error_return;
-               }
-       }
-
-       /*
-        * Truncate file.  Must have write permission and not be a directory.
-        */
-       if (mask & ATTR_SIZE) {
-               /* Short circuit the truncate case for zero length files */
-               if (iattr->ia_size == 0 &&
-                   ip->i_size == 0 && ip->i_d.di_nextents == 0) {
-                       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-                       lock_flags &= ~XFS_ILOCK_EXCL;
-                       if (mask & ATTR_CTIME) {
-                               inode->i_mtime = inode->i_ctime =
-                                               current_fs_time(inode->i_sb);
-                               xfs_mark_inode_dirty_sync(ip);
-                       }
-                       code = 0;
-                       goto error_return;
-               }
-
-               if (S_ISDIR(ip->i_d.di_mode)) {
-                       code = XFS_ERROR(EISDIR);
-                       goto error_return;
-               } else if (!S_ISREG(ip->i_d.di_mode)) {
-                       code = XFS_ERROR(EINVAL);
-                       goto error_return;
-               }
-
-               /*
-                * Make sure that the dquots are attached to the inode.
-                */
-               code = xfs_qm_dqattach_locked(ip, 0);
-               if (code)
-                       goto error_return;
-
-               /*
-                * Now we can make the changes.  Before we join the inode
-                * to the transaction, if ATTR_SIZE is set then take care of
-                * the part of the truncation that must be done without the
-                * inode lock.  This needs to be done before joining the inode
-                * to the transaction, because the inode cannot be unlocked
-                * once it is a part of the transaction.
-                */
-               if (iattr->ia_size > ip->i_size) {
-                       /*
-                        * Do the first part of growing a file: zero any data
-                        * in the last block that is beyond the old EOF.  We
-                        * need to do this before the inode is joined to the
-                        * transaction to modify the i_size.
-                        */
-                       code = xfs_zero_eof(ip, iattr->ia_size, ip->i_size);
-                       if (code)
-                               goto error_return;
-               }
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-               lock_flags &= ~XFS_ILOCK_EXCL;
-
-               /*
-                * We are going to log the inode size change in this
-                * transaction so any previous writes that are beyond the on
-                * disk EOF and the new EOF that have not been written out need
-                * to be written here. If we do not write the data out, we
-                * expose ourselves to the null files problem.
-                *
-                * Only flush from the on disk size to the smaller of the in
-                * memory file size or the new size as that's the range we
-                * really care about here and prevents waiting for other data
-                * not within the range we care about here.
-                */
-               if (ip->i_size != ip->i_d.di_size &&
-                   iattr->ia_size > ip->i_d.di_size) {
-                       code = xfs_flush_pages(ip,
-                                       ip->i_d.di_size, iattr->ia_size,
-                                       XBF_ASYNC, FI_NONE);
-                       if (code)
-                               goto error_return;
-               }
-
-               /* wait for all I/O to complete */
-               xfs_ioend_wait(ip);
-
-               code = -block_truncate_page(inode->i_mapping, iattr->ia_size,
-                                           xfs_get_blocks);
-               if (code)
-                       goto error_return;
-
-               tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
-               code = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
-                                        XFS_TRANS_PERM_LOG_RES,
-                                        XFS_ITRUNCATE_LOG_COUNT);
-               if (code)
-                       goto error_return;
-
-               truncate_setsize(inode, iattr->ia_size);
-
-               commit_flags = XFS_TRANS_RELEASE_LOG_RES;
-               lock_flags |= XFS_ILOCK_EXCL;
-
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-
-               xfs_trans_ijoin(tp, ip);
-
-               /*
-                * Only change the c/mtime if we are changing the size
-                * or we are explicitly asked to change it. This handles
-                * the semantic difference between truncate() and ftruncate()
-                * as implemented in the VFS.
-                *
-                * The regular truncate() case without ATTR_CTIME and ATTR_MTIME
-                * is a special case where we need to update the times despite
-                * not having these flags set.  For all other operations the
-                * VFS set these flags explicitly if it wants a timestamp
-                * update.
-                */
-               if (iattr->ia_size != ip->i_size &&
-                   (!(mask & (ATTR_CTIME | ATTR_MTIME)))) {
-                       iattr->ia_ctime = iattr->ia_mtime =
-                               current_fs_time(inode->i_sb);
-                       mask |= ATTR_CTIME | ATTR_MTIME;
-               }
-
-               if (iattr->ia_size > ip->i_size) {
-                       ip->i_d.di_size = iattr->ia_size;
-                       ip->i_size = iattr->ia_size;
-                       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-               } else if (iattr->ia_size <= ip->i_size ||
-                          (iattr->ia_size == 0 && ip->i_d.di_nextents)) {
-                       /*
-                        * signal a sync transaction unless
-                        * we're truncating an already unlinked
-                        * file on a wsync filesystem
-                        */
-                       code = xfs_itruncate_finish(&tp, ip, iattr->ia_size,
-                                           XFS_DATA_FORK,
-                                           ((ip->i_d.di_nlink != 0 ||
-                                             !(mp->m_flags & XFS_MOUNT_WSYNC))
-                                            ? 1 : 0));
-                       if (code)
-                               goto abort_return;
-                       /*
-                        * Truncated "down", so we're removing references
-                        * to old data here - if we now delay flushing for
-                        * a long time, we expose ourselves unduly to the
-                        * notorious NULL files problem.  So, we mark this
-                        * vnode and flush it when the file is closed, and
-                        * do not wait the usual (long) time for writeout.
-                        */
-                       xfs_iflags_set(ip, XFS_ITRUNCATED);
-               }
-       } else if (tp) {
-               xfs_trans_ijoin(tp, ip);
-       }
-
-       /*
-        * Change file ownership.  Must be the owner or privileged.
-        */
-       if (mask & (ATTR_UID|ATTR_GID)) {
-               /*
-                * CAP_FSETID overrides the following restrictions:
-                *
-                * The set-user-ID and set-group-ID bits of a file will be
-                * cleared upon successful return from chown()
-                */
-               if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) &&
-                   !capable(CAP_FSETID)) {
-                       ip->i_d.di_mode &= ~(S_ISUID|S_ISGID);
-               }
-
-               /*
-                * Change the ownerships and register quota modifications
-                * in the transaction.
-                */
-               if (iuid != uid) {
-                       if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_UQUOTA_ON(mp)) {
-                               ASSERT(mask & ATTR_UID);
-                               ASSERT(udqp);
-                               olddquot1 = xfs_qm_vop_chown(tp, ip,
-                                                       &ip->i_udquot, udqp);
-                       }
-                       ip->i_d.di_uid = uid;
-                       inode->i_uid = uid;
-               }
-               if (igid != gid) {
-                       if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_GQUOTA_ON(mp)) {
-                               ASSERT(!XFS_IS_PQUOTA_ON(mp));
-                               ASSERT(mask & ATTR_GID);
-                               ASSERT(gdqp);
-                               olddquot2 = xfs_qm_vop_chown(tp, ip,
-                                                       &ip->i_gdquot, gdqp);
-                       }
-                       ip->i_d.di_gid = gid;
-                       inode->i_gid = gid;
-               }
-       }
-
-       /*
-        * Change file access modes.
-        */
-       if (mask & ATTR_MODE) {
-               umode_t mode = iattr->ia_mode;
-
-               if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
-                       mode &= ~S_ISGID;
-
-               ip->i_d.di_mode &= S_IFMT;
-               ip->i_d.di_mode |= mode & ~S_IFMT;
-
-               inode->i_mode &= S_IFMT;
-               inode->i_mode |= mode & ~S_IFMT;
-       }
-
-       /*
-        * Change file access or modified times.
-        */
-       if (mask & ATTR_ATIME) {
-               inode->i_atime = iattr->ia_atime;
-               ip->i_d.di_atime.t_sec = iattr->ia_atime.tv_sec;
-               ip->i_d.di_atime.t_nsec = iattr->ia_atime.tv_nsec;
-               ip->i_update_core = 1;
-       }
-       if (mask & ATTR_CTIME) {
-               inode->i_ctime = iattr->ia_ctime;
-               ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec;
-               ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec;
-               ip->i_update_core = 1;
-       }
-       if (mask & ATTR_MTIME) {
-               inode->i_mtime = iattr->ia_mtime;
-               ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec;
-               ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec;
-               ip->i_update_core = 1;
-       }
-
-       /*
-        * And finally, log the inode core if any attribute in it
-        * has been changed.
-        */
-       if (mask & (ATTR_UID|ATTR_GID|ATTR_MODE|
-                   ATTR_ATIME|ATTR_CTIME|ATTR_MTIME))
-               xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-
-       XFS_STATS_INC(xs_ig_attrchg);
-
-       /*
-        * If this is a synchronous mount, make sure that the
-        * transaction goes to disk before returning to the user.
-        * This is slightly sub-optimal in that truncates require
-        * two sync transactions instead of one for wsync filesystems.
-        * One for the truncate and one for the timestamps since we
-        * don't want to change the timestamps unless we're sure the
-        * truncate worked.  Truncates are less than 1% of the laddis
-        * mix so this probably isn't worth the trouble to optimize.
-        */
-       code = 0;
-       if (mp->m_flags & XFS_MOUNT_WSYNC)
-               xfs_trans_set_sync(tp);
-
-       code = xfs_trans_commit(tp, commit_flags);
-
-       xfs_iunlock(ip, lock_flags);
-
-       /*
-        * Release any dquot(s) the inode had kept before chown.
-        */
-       xfs_qm_dqrele(olddquot1);
-       xfs_qm_dqrele(olddquot2);
-       xfs_qm_dqrele(udqp);
-       xfs_qm_dqrele(gdqp);
-
-       if (code)
-               return code;
-
-       /*
-        * XXX(hch): Updating the ACL entries is not atomic vs the i_mode
-        *           update.  We could avoid this with linked transactions
-        *           and passing down the transaction pointer all the way
-        *           to attr_set.  No previous user of the generic
-        *           Posix ACL code seems to care about this issue either.
-        */
-       if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) {
-               code = -xfs_acl_chmod(inode);
-               if (code)
-                       return XFS_ERROR(code);
-       }
-
-       return 0;
-
- abort_return:
-       commit_flags |= XFS_TRANS_ABORT;
- error_return:
-       xfs_qm_dqrele(udqp);
-       xfs_qm_dqrele(gdqp);
-       if (tp) {
-               xfs_trans_cancel(tp, commit_flags);
-       }
-       if (lock_flags != 0) {
-               xfs_iunlock(ip, lock_flags);
-       }
-       return code;
-}
-
 /*
  * The maximum pathlen is 1024 bytes. Since the minimum file system
  * blocksize is 512 bytes, we can get a max of 2 extents back from
@@ -621,13 +197,6 @@ xfs_free_eofblocks(
                 */
                tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
 
-               /*
-                * Do the xfs_itruncate_start() call before
-                * reserving any log space because
-                * itruncate_start will call into the buffer
-                * cache and we can't
-                * do that within a transaction.
-                */
                if (flags & XFS_FREE_EOF_TRYLOCK) {
                        if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
                                xfs_trans_cancel(tp, 0);
@@ -636,13 +205,6 @@ xfs_free_eofblocks(
                } else {
                        xfs_ilock(ip, XFS_IOLOCK_EXCL);
                }
-               error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
-                                   ip->i_size);
-               if (error) {
-                       xfs_trans_cancel(tp, 0);
-                       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-                       return error;
-               }
 
                error = xfs_trans_reserve(tp, 0,
                                          XFS_ITRUNCATE_LOG_RES(mp),
@@ -953,40 +515,62 @@ xfs_release(
                 * If we previously truncated this file and removed old data
                 * in the process, we want to initiate "early" writeout on
                 * the last close.  This is an attempt to combat the notorious
-                * NULL files problem which is particularly noticable from a
+                * NULL files problem which is particularly noticeable from a
                 * truncate down, buffered (re-)write (delalloc), followed by
                 * a crash.  What we are effectively doing here is
                 * significantly reducing the time window where we'd otherwise
                 * be exposed to that problem.
                 */
                truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED);
-               if (truncated && VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0)
-                       xfs_flush_pages(ip, 0, -1, XBF_ASYNC, FI_NONE);
+               if (truncated) {
+                       xfs_iflags_clear(ip, XFS_IDIRTY_RELEASE);
+                       if (VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0)
+                               xfs_flush_pages(ip, 0, -1, XBF_ASYNC, FI_NONE);
+               }
        }
 
-       if (ip->i_d.di_nlink != 0) {
-               if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&
-                    ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 ||
-                      ip->i_delayed_blks > 0)) &&
-                    (ip->i_df.if_flags & XFS_IFEXTENTS))  &&
-                   (!(ip->i_d.di_flags &
-                               (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) {
+       if (ip->i_d.di_nlink == 0)
+               return 0;
 
-                       /*
-                        * If we can't get the iolock just skip truncating
-                        * the blocks past EOF because we could deadlock
-                        * with the mmap_sem otherwise.  We'll get another
-                        * chance to drop them once the last reference to
-                        * the inode is dropped, so we'll never leak blocks
-                        * permanently.
-                        */
-                       error = xfs_free_eofblocks(mp, ip,
-                                                  XFS_FREE_EOF_TRYLOCK);
-                       if (error)
-                               return error;
-               }
-       }
+       if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&
+            ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 ||
+              ip->i_delayed_blks > 0)) &&
+            (ip->i_df.if_flags & XFS_IFEXTENTS))  &&
+           (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) {
 
+               /*
+                * If we can't get the iolock just skip truncating the blocks
+                * past EOF because we could deadlock with the mmap_sem
+                * otherwise.  We'll get another chance to drop them once the
+                * last reference to the inode is dropped, so we'll never leak
+                * blocks permanently.
+                *
+                * Further, check if the inode is being opened, written and
+                * closed frequently and we have delayed allocation blocks
+                * outstanding (e.g. streaming writes from the NFS server),
+                * truncating the blocks past EOF will cause fragmentation to
+                * occur.
+                *
+                * In this case don't do the truncation, either, but we have to
+                * be careful how we detect this case. Blocks beyond EOF show
+                * up as i_delayed_blks even when the inode is clean, so we
+                * need to truncate them away first before checking for a dirty
+                * release. Hence on the first dirty close we will still remove
+                * the speculative allocation, but after that we will leave it
+                * in place.
+                */
+               if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE))
+                       return 0;
+
+               error = xfs_free_eofblocks(mp, ip,
+                                          XFS_FREE_EOF_TRYLOCK);
+               if (error)
+                       return error;
+
+               /* delalloc blocks after truncation means it really is dirty */
+               if (ip->i_delayed_blks)
+                       xfs_iflags_set(ip, XFS_IDIRTY_RELEASE);
+       }
        return 0;
 }
 
@@ -1062,20 +646,9 @@ xfs_inactive(
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
        if (truncate) {
-               /*
-                * Do the xfs_itruncate_start() call before
-                * reserving any log space because itruncate_start
-                * will call into the buffer cache and we can't
-                * do that within a transaction.
-                */
                xfs_ilock(ip, XFS_IOLOCK_EXCL);
 
-               error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0);
-               if (error) {
-                       xfs_trans_cancel(tp, 0);
-                       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-                       return VN_INACTIVE_CACHE;
-               }
+               xfs_ioend_wait(ip);
 
                error = xfs_trans_reserve(tp, 0,
                                          XFS_ITRUNCATE_LOG_RES(mp),
@@ -1170,9 +743,8 @@ xfs_inactive(
                 * inode might be lost for a long time or forever.
                 */
                if (!XFS_FORCED_SHUTDOWN(mp)) {
-                       cmn_err(CE_NOTE,
-               "xfs_inactive:  xfs_ifree() returned an error = %d on %s",
-                               error, mp->m_fsname);
+                       xfs_notice(mp, "%s: xfs_ifree returned error %d",
+                               __func__, error);
                        xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
                }
                xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
@@ -1189,12 +761,12 @@ xfs_inactive(
                 */
                error = xfs_bmap_finish(&tp,  &free_list, &committed);
                if (error)
-                       xfs_fs_cmn_err(CE_NOTE, mp, "xfs_inactive: "
-                               "xfs_bmap_finish() returned error %d", error);
+                       xfs_notice(mp, "%s: xfs_bmap_finish returned error %d",
+                               __func__, error);
                error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
                if (error)
-                       xfs_fs_cmn_err(CE_NOTE, mp, "xfs_inactive: "
-                               "xfs_trans_commit() returned error %d", error);
+                       xfs_notice(mp, "%s: xfs_trans_commit returned error %d",
+                               __func__, error);
        }
 
        /*
@@ -1256,8 +828,7 @@ xfs_create(
        struct xfs_name         *name,
        mode_t                  mode,
        xfs_dev_t               rdev,
-       xfs_inode_t             **ipp,
-       cred_t                  *credp)
+       xfs_inode_t             **ipp)
 {
        int                     is_dir = S_ISDIR(mode);
        struct xfs_mount        *mp = dp->i_mount;
@@ -1269,7 +840,7 @@ xfs_create(
        boolean_t               unlock_dp_on_error = B_FALSE;
        uint                    cancel_flags;
        int                     committed;
-       xfs_prid_t              prid;
+       prid_t                  prid;
        struct xfs_dquot        *udqp = NULL;
        struct xfs_dquot        *gdqp = NULL;
        uint                    resblks;
@@ -1282,9 +853,9 @@ xfs_create(
                return XFS_ERROR(EIO);
 
        if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
-               prid = dp->i_d.di_projid;
+               prid = xfs_get_projid(dp);
        else
-               prid = dfltprid;
+               prid = XFS_PROJID_DEFAULT;
 
        /*
         * Make sure that we have allocated dquot(s) on disk.
@@ -1292,7 +863,7 @@ xfs_create(
        error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
                        XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
        if (error)
-               goto std_return;
+               return error;
 
        if (is_dir) {
                rdev = 0;
@@ -1363,7 +934,7 @@ xfs_create(
         * entry pointing to them, but a directory also the "." entry
         * pointing to itself.
         */
-       error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, credp,
+       error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev,
                               prid, resblks > 0, &ip, &committed);
        if (error) {
                if (error == ENOSPC)
@@ -1372,12 +943,6 @@ xfs_create(
        }
 
        /*
-        * At this point, we've gotten a newly allocated inode.
-        * It is locked (and joined to the transaction).
-        */
-       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-
-       /*
         * Now we join the directory inode to the transaction.  We do not do it
         * earlier because xfs_dir_ialloc might commit the previous transaction
         * (and release all the locks).  An error from here on will result in
@@ -1422,22 +987,13 @@ xfs_create(
         */
        xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
 
-       /*
-        * xfs_trans_commit normally decrements the vnode ref count
-        * when it unlocks the inode. Since we want to return the
-        * vnode to the caller, we bump the vnode ref count now.
-        */
-       IHOLD(ip);
-
        error = xfs_bmap_finish(&tp, &free_list, &committed);
        if (error)
-               goto out_abort_rele;
+               goto out_bmap_cancel;
 
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       if (error) {
-               IRELE(ip);
-               goto out_dqrele;
-       }
+       if (error)
+               goto out_release_inode;
 
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
@@ -1451,27 +1007,21 @@ xfs_create(
        cancel_flags |= XFS_TRANS_ABORT;
  out_trans_cancel:
        xfs_trans_cancel(tp, cancel_flags);
- out_dqrele:
+ out_release_inode:
+       /*
+        * Wait until after the current transaction is aborted to
+        * release the inode.  This prevents recursive transactions
+        * and deadlocks from xfs_inactive.
+        */
+       if (ip)
+               IRELE(ip);
+
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
 
        if (unlock_dp_on_error)
                xfs_iunlock(dp, XFS_ILOCK_EXCL);
- std_return:
        return error;
-
- out_abort_rele:
-       /*
-        * Wait until after the current transaction is aborted to
-        * release the inode.  This prevents recursive transactions
-        * and deadlocks from xfs_inactive.
-        */
-       xfs_bmap_cancel(&free_list);
-       cancel_flags |= XFS_TRANS_ABORT;
-       xfs_trans_cancel(tp, cancel_flags);
-       IRELE(ip);
-       unlock_dp_on_error = B_FALSE;
-       goto out_dqrele;
 }
 
 #ifdef DEBUG
@@ -1883,7 +1433,7 @@ xfs_link(
         * the tree quota mechanism could be circumvented.
         */
        if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
-                    (tdp->i_d.di_projid != sip->i_d.di_projid))) {
+                    (xfs_get_projid(tdp) != xfs_get_projid(sip)))) {
                error = XFS_ERROR(EXDEV);
                goto error_return;
        }
@@ -1936,8 +1486,7 @@ xfs_symlink(
        struct xfs_name         *link_name,
        const char              *target_path,
        mode_t                  mode,
-       xfs_inode_t             **ipp,
-       cred_t                  *credp)
+       xfs_inode_t             **ipp)
 {
        xfs_mount_t             *mp = dp->i_mount;
        xfs_trans_t             *tp;
@@ -1958,7 +1507,7 @@ xfs_symlink(
        int                     byte_cnt;
        int                     n;
        xfs_buf_t               *bp;
-       xfs_prid_t              prid;
+       prid_t                  prid;
        struct xfs_dquot        *udqp, *gdqp;
        uint                    resblks;
 
@@ -1981,9 +1530,9 @@ xfs_symlink(
 
        udqp = gdqp = NULL;
        if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
-               prid = dp->i_d.di_projid;
+               prid = xfs_get_projid(dp);
        else
-               prid = (xfs_prid_t)dfltprid;
+               prid = XFS_PROJID_DEFAULT;
 
        /*
         * Make sure that we have allocated dquot(s) on disk.
@@ -2049,8 +1598,8 @@ xfs_symlink(
        /*
         * Allocate an inode for the symlink.
         */
-       error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT),
-                              1, 0, credp, prid, resblks > 0, &ip, NULL);
+       error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0,
+                              prid, resblks > 0, &ip, NULL);
        if (error) {
                if (error == ENOSPC)
                        goto error_return;
@@ -2097,9 +1646,8 @@ xfs_symlink(
                                  XFS_BMAPI_WRITE | XFS_BMAPI_METADATA,
                                  &first_block, resblks, mval, &nmaps,
                                  &free_list);
-               if (error) {
-                       goto error1;
-               }
+               if (error)
+                       goto error2;
 
                if (resblks)
                        resblks -= fs_blocks;
@@ -2131,7 +1679,7 @@ xfs_symlink(
        error = xfs_dir_createname(tp, dp, link_name, ip->i_ino,
                                        &first_block, &free_list, resblks);
        if (error)
-               goto error1;
+               goto error2;
        xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
        xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
 
@@ -2144,13 +1692,6 @@ xfs_symlink(
                xfs_trans_set_sync(tp);
        }
 
-       /*
-        * xfs_trans_commit normally decrements the vnode ref count
-        * when it unlocks the inode. Since we want to return the
-        * vnode to the caller, we bump the vnode ref count now.
-        */
-       IHOLD(ip);
-
        error = xfs_bmap_finish(&tp, &free_list, &committed);
        if (error) {
                goto error2;
@@ -2462,7 +2003,7 @@ xfs_zero_remaining_bytes(
                XFS_BUF_READ(bp);
                XFS_BUF_SET_ADDR(bp, xfs_fsb_to_db(ip, imap.br_startblock));
                xfsbdstrat(mp, bp);
-               error = xfs_iowait(bp);
+               error = xfs_buf_iowait(bp);
                if (error) {
                        xfs_ioerror_alert("xfs_zero_remaining_bytes(read)",
                                          mp, bp, XFS_BUF_ADDR(bp));
@@ -2475,7 +2016,7 @@ xfs_zero_remaining_bytes(
                XFS_BUF_UNREAD(bp);
                XFS_BUF_WRITE(bp);
                xfsbdstrat(mp, bp);
-               error = xfs_iowait(bp);
+               error = xfs_buf_iowait(bp);
                if (error) {
                        xfs_ioerror_alert("xfs_zero_remaining_bytes(write)",
                                          mp, bp, XFS_BUF_ADDR(bp));
@@ -2794,7 +2335,7 @@ xfs_change_file_space(
                iattr.ia_valid = ATTR_SIZE;
                iattr.ia_size = startoffset;
 
-               error = xfs_setattr(ip, &iattr, attr_flags);
+               error = xfs_setattr_size(ip, &iattr, attr_flags);
 
                if (error)
                        return error;
@@ -2844,7 +2385,8 @@ xfs_change_file_space(
                ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC;
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-       xfs_trans_set_sync(tp);
+       if (attr_flags & XFS_ATTR_SYNC)
+               xfs_trans_set_sync(tp);
 
        error = xfs_trans_commit(tp, 0);