xfs: kill xfs_itruncate_start
[linux-2.6.git] / fs / xfs / xfs_vnodeops.c
index 588bb4a..45b8ac6 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
 #include "xfs_itable.h"
-#include "xfs_btree.h"
 #include "xfs_ialloc.h"
 #include "xfs_alloc.h"
 #include "xfs_bmap.h"
+#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_rw.h"
 #include "xfs_error.h"
 #include "xfs_log_priv.h"
 #include "xfs_filestream.h"
 #include "xfs_vnodeops.h"
-
-int
-xfs_open(
-       xfs_inode_t     *ip)
-{
-       int             mode;
-
-       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
-               return XFS_ERROR(EIO);
-
-       /*
-        * If it's a directory with any blocks, read-ahead block 0
-        * as we're almost certain to have the next operation be a read there.
-        */
-       if (S_ISDIR(ip->i_d.di_mode) && ip->i_d.di_nextents > 0) {
-               mode = xfs_ilock_map_shared(ip);
-               if (ip->i_d.di_nextents > 0)
-                       (void)xfs_da_reada_buf(NULL, ip, 0, XFS_DATA_FORK);
-               xfs_iunlock(ip, mode);
-       }
-       return 0;
-}
-
-int
-xfs_setattr(
-       struct xfs_inode        *ip,
-       struct iattr            *iattr,
-       int                     flags,
-       cred_t                  *credp)
-{
-       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;
-       int                     timeflags = 0;
-       struct xfs_dquot        *udqp, *gdqp, *olddquot1, *olddquot2;
-       int                     file_owner;
-       int                     need_iolock = 1;
-
-       xfs_itrace_entry(ip);
-
-       if (mp->m_flags & XFS_MOUNT_RDONLY)
-               return XFS_ERROR(EROFS);
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
-
-       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_DQVOPALLOC(mp, 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)) {
-               if ((mask != (ATTR_CTIME|ATTR_ATIME|ATTR_MTIME)) ||
-                   (mp->m_flags & XFS_MOUNT_WSYNC)) {
-                       tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
-                       commit_flags = 0;
-                       if ((code = xfs_trans_reserve(tp, 0,
-                                                    XFS_ICHANGE_LOG_RES(mp), 0,
-                                                    0, 0))) {
-                               lock_flags = 0;
-                               goto error_return;
-                       }
-               }
-       } else {
-               if (DM_EVENT_ENABLED(ip, DM_EVENT_TRUNCATE) &&
-                   !(flags & XFS_ATTR_DMI)) {
-                       int dmflags = AT_DELAY_FLAG(flags) | DM_SEM_FLAG_WR;
-                       code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, ip,
-                               iattr->ia_size, 0, dmflags, NULL);
-                       if (code) {
-                               lock_flags = 0;
-                               goto error_return;
-                       }
-               }
-               if (need_iolock)
-                       lock_flags |= XFS_IOLOCK_EXCL;
-       }
-
-       xfs_ilock(ip, lock_flags);
-
-       /* boolean: are we the file owner? */
-       file_owner = (current_fsuid(credp) == ip->i_d.di_uid);
-
-       /*
-        * Change various properties of a file.
-        * Only the owner or users with CAP_FOWNER
-        * capability may do these things.
-        */
-       if (mask & (ATTR_MODE|ATTR_UID|ATTR_GID)) {
-               /*
-                * CAP_FOWNER overrides the following restrictions:
-                *
-                * The user ID of the calling process must be equal
-                * to the file owner ID, except in cases where the
-                * CAP_FSETID capability is applicable.
-                */
-               if (!file_owner && !capable(CAP_FOWNER)) {
-                       code = XFS_ERROR(EPERM);
-                       goto error_return;
-               }
-
-               /*
-                * CAP_FSETID overrides the following restrictions:
-                *
-                * The effective user ID of the calling process shall match
-                * the file owner when setting the set-user-ID and
-                * set-group-ID bits on that file.
-                *
-                * The effective group ID or one of the supplementary group
-                * IDs of the calling process shall match the group owner of
-                * the file when setting the set-group-ID bit on that file
-                */
-               if (mask & ATTR_MODE) {
-                       mode_t m = 0;
-
-                       if ((iattr->ia_mode & S_ISUID) && !file_owner)
-                               m |= S_ISUID;
-                       if ((iattr->ia_mode & S_ISGID) &&
-                           !in_group_p((gid_t)ip->i_d.di_gid))
-                               m |= S_ISGID;
-#if 0
-                       /* Linux allows this, Irix doesn't. */
-                       if ((iattr->ia_mode & S_ISVTX) && !S_ISDIR(ip->i_d.di_mode))
-                               m |= S_ISVTX;
-#endif
-                       if (m && !capable(CAP_FSETID))
-                               iattr->ia_mode &= ~m;
-               }
-       }
-
-       /*
-        * Change file ownership.  Must be the owner or privileged.
-        * If the system was configured with the "restricted_chown"
-        * option, the owner is not permitted to give away the file,
-        * and can change the group id only to a group of which he
-        * or she is a member.
-        */
-       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;
-
-               /*
-                * CAP_CHOWN overrides the following restrictions:
-                *
-                * If _POSIX_CHOWN_RESTRICTED is defined, this capability
-                * shall override the restriction that a process cannot
-                * change the user ID of a file it owns and the restriction
-                * that the group ID supplied to the chown() function
-                * shall be equal to either the group ID or one of the
-                * supplementary group IDs of the calling process.
-                */
-               if (restricted_chown &&
-                   (iuid != uid || (igid != gid &&
-                                    !in_group_p((gid_t)gid))) &&
-                   !capable(CAP_CHOWN)) {
-                       code = XFS_ERROR(EPERM);
-                       goto error_return;
-               }
-               /*
-                * Do a quota reservation only if uid/gid is actually
-                * going to change.
-                */
-               if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
-                   (XFS_IS_GQUOTA_ON(mp) && igid != gid)) {
-                       ASSERT(tp);
-                       code = XFS_QM_DQVOPCHOWNRESV(mp, 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)
-                               xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-                       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.
-                */
-               if ((code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED)))
-                       goto error_return;
-       }
-
-       /*
-        * Change file access or modified times.
-        */
-       if (mask & (ATTR_ATIME|ATTR_MTIME)) {
-               if (!file_owner) {
-                       if ((mask & (ATTR_MTIME_SET|ATTR_ATIME_SET)) &&
-                           !capable(CAP_FOWNER)) {
-                               code = XFS_ERROR(EPERM);
-                               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 (mask & ATTR_SIZE) {
-               code = 0;
-               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);
-               }
-               xfs_iunlock(ip, 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 (!code &&
-                   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,
-                                       XFS_B_ASYNC, FI_NONE);
-               }
-
-               /* wait for all I/O to complete */
-               vn_iowait(ip);
-
-               if (!code)
-                       code = xfs_itruncate_data(ip, iattr->ia_size);
-               if (code) {
-                       ASSERT(tp == NULL);
-                       lock_flags &= ~XFS_ILOCK_EXCL;
-                       ASSERT(lock_flags == XFS_IOLOCK_EXCL);
-                       goto error_return;
-               }
-               tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
-               if ((code = xfs_trans_reserve(tp, 0,
-                                            XFS_ITRUNCATE_LOG_RES(mp), 0,
-                                            XFS_TRANS_PERM_LOG_RES,
-                                            XFS_ITRUNCATE_LOG_COUNT))) {
-                       xfs_trans_cancel(tp, 0);
-                       if (need_iolock)
-                               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-                       return code;
-               }
-               commit_flags = XFS_TRANS_RELEASE_LOG_RES;
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-       }
-
-       if (tp) {
-               xfs_trans_ijoin(tp, ip, lock_flags);
-               xfs_trans_ihold(tp, ip);
-       }
-
-       /*
-        * Truncate file.  Must have write permission and not be a directory.
-        */
-       if (mask & ATTR_SIZE) {
-               /*
-                * 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.
-                */
-               if (iattr->ia_size != ip->i_size || (mask & ATTR_CTIME))
-                       timeflags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;
-
-               if (iattr->ia_size > ip->i_size) {
-                       ip->i_d.di_size = iattr->ia_size;
-                       ip->i_size = iattr->ia_size;
-                       if (!(flags & XFS_ATTR_DMI))
-                               xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
-                       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);
-               }
-       }
-
-       /*
-        * Change file access modes.
-        */
-       if (mask & ATTR_MODE) {
-               ip->i_d.di_mode &= S_IFMT;
-               ip->i_d.di_mode |= iattr->ia_mode & ~S_IFMT;
-
-               inode->i_mode &= S_IFMT;
-               inode->i_mode |= iattr->ia_mode & ~S_IFMT;
-
-               xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE);
-               timeflags |= XFS_ICHGTIME_CHG;
-       }
-
-       /*
-        * Change file ownership.  Must be the owner or privileged.
-        * If the system was configured with the "restricted_chown"
-        * option, the owner is not permitted to give away the file,
-        * and can change the group id only to a group of which he
-        * or she is a member.
-        */
-       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_UQUOTA_ON(mp)) {
-                               ASSERT(mask & ATTR_UID);
-                               ASSERT(udqp);
-                               olddquot1 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
-                                                       &ip->i_udquot, udqp);
-                       }
-                       ip->i_d.di_uid = uid;
-                       inode->i_uid = uid;
-               }
-               if (igid != gid) {
-                       if (XFS_IS_GQUOTA_ON(mp)) {
-                               ASSERT(!XFS_IS_PQUOTA_ON(mp));
-                               ASSERT(mask & ATTR_GID);
-                               ASSERT(gdqp);
-                               olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
-                                                       &ip->i_gdquot, gdqp);
-                       }
-                       ip->i_d.di_gid = gid;
-                       inode->i_gid = gid;
-               }
-
-               xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE);
-               timeflags |= XFS_ICHGTIME_CHG;
-       }
-
-
-       /*
-        * Change file access or modified times.
-        */
-       if (mask & (ATTR_ATIME|ATTR_MTIME)) {
-               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_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;
-                       timeflags &= ~XFS_ICHGTIME_MOD;
-                       timeflags |= XFS_ICHGTIME_CHG;
-               }
-               if (tp && (mask & (ATTR_MTIME_SET|ATTR_ATIME_SET)))
-                       xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE);
-       }
-
-       /*
-        * Change file inode change time only if ATTR_CTIME set
-        * AND we have been called by a DMI function.
-        */
-
-       if ((flags & XFS_ATTR_DMI) && (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;
-               timeflags &= ~XFS_ICHGTIME_CHG;
-       }
-
-       /*
-        * Send out timestamp changes that need to be set to the
-        * current time.  Not done when called by a DMI function.
-        */
-       if (timeflags && !(flags & XFS_ATTR_DMI))
-               xfs_ichgtime(ip, timeflags);
-
-       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 (tp) {
-               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(mp, olddquot1);
-       XFS_QM_DQRELE(mp, olddquot2);
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
-
-       if (code) {
-               return code;
-       }
-
-       if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE) &&
-           !(flags & XFS_ATTR_DMI)) {
-               (void) XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL,
-                                       NULL, DM_RIGHT_NULL, NULL, NULL,
-                                       0, 0, AT_DELAY_FLAG(flags));
-       }
-       return 0;
-
- abort_return:
-       commit_flags |= XFS_TRANS_ABORT;
-       /* FALLTHROUGH */
- error_return:
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
-       if (tp) {
-               xfs_trans_cancel(tp, commit_flags);
-       }
-       if (lock_flags != 0) {
-               xfs_iunlock(ip, lock_flags);
-       }
-       return code;
-}
+#include "xfs_trace.h"
 
 /*
  * The maximum pathlen is 1024 bytes. Since the minimum file system
@@ -625,7 +73,7 @@ xfs_readlink_bmap(
        int             error = 0;
 
        error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), 0, NULL, 0,
-                       mval, &nmaps, NULL, NULL);
+                       mval, &nmaps, NULL);
        if (error)
                goto out;
 
@@ -633,7 +81,8 @@ xfs_readlink_bmap(
                d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
                byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
 
-               bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0);
+               bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt),
+                                 XBF_LOCK | XBF_MAPPED | XBF_DONT_BLOCK);
                error = XFS_BUF_GETERROR(bp);
                if (error) {
                        xfs_ioerror_alert("xfs_readlink",
@@ -665,7 +114,7 @@ xfs_readlink(
        int             pathlen;
        int             error = 0;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_readlink(ip);
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
@@ -692,126 +141,16 @@ xfs_readlink(
 }
 
 /*
- * xfs_fsync
- *
- * This is called to sync the inode and its data out to disk.  We need to hold
- * the I/O lock while flushing the data, and the inode lock while flushing the
- * inode.  The inode lock CANNOT be held while flushing the data, so acquire
- * after we're done with that.
+ * Flags for xfs_free_eofblocks
  */
-int
-xfs_fsync(
-       xfs_inode_t     *ip)
-{
-       xfs_trans_t     *tp;
-       int             error;
-       int             log_flushed = 0, changed = 1;
-
-       xfs_itrace_entry(ip);
-
-       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
-               return XFS_ERROR(EIO);
-
-       /* capture size updates in I/O completion before writing the inode. */
-       error = filemap_fdatawait(VFS_I(ip)->i_mapping);
-       if (error)
-               return XFS_ERROR(error);
-
-       /*
-        * We always need to make sure that the required inode state is safe on
-        * disk.  The vnode might be clean but we still might need to force the
-        * log because of committed transactions that haven't hit the disk yet.
-        * Likewise, there could be unflushed non-transactional changes to the
-        * inode core that have to go to disk and this requires us to issue
-        * a synchronous transaction to capture these changes correctly.
-        *
-        * This code relies on the assumption that if the update_* fields
-        * of the inode are clear and the inode is unpinned then it is clean
-        * and no action is required.
-        */
-       xfs_ilock(ip, XFS_ILOCK_SHARED);
-
-       if (!(ip->i_update_size || ip->i_update_core)) {
-               /*
-                * Timestamps/size haven't changed since last inode flush or
-                * inode transaction commit.  That means either nothing got
-                * written or a transaction committed which caught the updates.
-                * If the latter happened and the transaction hasn't hit the
-                * disk yet, the inode will be still be pinned.  If it is,
-                * force the log.
-                */
-
-               xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
-               if (xfs_ipincount(ip)) {
-                       error = _xfs_log_force(ip->i_mount, (xfs_lsn_t)0,
-                                     XFS_LOG_FORCE | XFS_LOG_SYNC,
-                                     &log_flushed);
-               } else {
-                       /*
-                        * If the inode is not pinned and nothing has changed
-                        * we don't need to flush the cache.
-                        */
-                       changed = 0;
-               }
-       } else  {
-               /*
-                * Kick off a transaction to log the inode core to get the
-                * updates.  The sync transaction will also force the log.
-                */
-               xfs_iunlock(ip, XFS_ILOCK_SHARED);
-               tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_FSYNC_TS);
-               error = xfs_trans_reserve(tp, 0,
-                               XFS_FSYNC_TS_LOG_RES(ip->i_mount), 0, 0, 0);
-               if (error) {
-                       xfs_trans_cancel(tp, 0);
-                       return error;
-               }
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-
-               /*
-                * Note - it's possible that we might have pushed ourselves out
-                * of the way during trans_reserve which would flush the inode.
-                * But there's no guarantee that the inode buffer has actually
-                * gone out yet (it's delwri).  Plus the buffer could be pinned
-                * anyway if it's part of an inode in another recent
-                * transaction.  So we play it safe and fire off the
-                * transaction anyway.
-                */
-               xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
-               xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-               xfs_trans_set_sync(tp);
-               error = _xfs_trans_commit(tp, 0, &log_flushed);
-
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       }
-
-       if ((ip->i_mount->m_flags & XFS_MOUNT_BARRIER) && changed) {
-               /*
-                * If the log write didn't issue an ordered tag we need
-                * to flush the disk cache for the data device now.
-                */
-               if (!log_flushed)
-                       xfs_blkdev_issue_flush(ip->i_mount->m_ddev_targp);
-
-               /*
-                * If this inode is on the RT dev we need to flush that
-                * cache as well.
-                */
-               if (XFS_IS_REALTIME_INODE(ip))
-                       xfs_blkdev_issue_flush(ip->i_mount->m_rtdev_targp);
-       }
-
-       return error;
-}
+#define XFS_FREE_EOF_TRYLOCK   (1<<0)
 
 /*
  * This is called by xfs_inactive to free any blocks beyond eof
  * when the link count isn't zero and by xfs_dm_punch_hole() when
  * punching a hole to EOF.
  */
-int
+STATIC int
 xfs_free_eofblocks(
        xfs_mount_t     *mp,
        xfs_inode_t     *ip,
@@ -824,7 +163,6 @@ xfs_free_eofblocks(
        xfs_filblks_t   map_len;
        int             nimaps;
        xfs_bmbt_irec_t imap;
-       int             use_iolock = (flags & XFS_FREE_EOF_LOCK);
 
        /*
         * Figure out if there are any blocks beyond the end
@@ -832,14 +170,14 @@ xfs_free_eofblocks(
         */
        end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_size));
        last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
-       map_len = last_fsb - end_fsb;
-       if (map_len <= 0)
+       if (last_fsb <= end_fsb)
                return 0;
+       map_len = last_fsb - end_fsb;
 
        nimaps = 1;
        xfs_ilock(ip, XFS_ILOCK_SHARED);
        error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0,
-                         NULL, 0, &imap, &nimaps, NULL, NULL);
+                         NULL, 0, &imap, &nimaps, NULL);
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
        if (!error && (nimaps != 0) &&
@@ -848,7 +186,8 @@ xfs_free_eofblocks(
                /*
                 * Attach the dquots to the inode up front.
                 */
-               if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+               error = xfs_qm_dqattach(ip, 0);
+               if (error)
                        return error;
 
                /*
@@ -858,22 +197,13 @@ 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 (use_iolock)
+               if (flags & XFS_FREE_EOF_TRYLOCK) {
+                       if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
+                               xfs_trans_cancel(tp, 0);
+                               return 0;
+                       }
+               } 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);
-                       if (use_iolock)
-                               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-                       return error;
                }
 
                error = xfs_trans_reserve(tp, 0,
@@ -888,10 +218,7 @@ xfs_free_eofblocks(
                }
 
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin(tp, ip,
-                               XFS_IOLOCK_EXCL |
-                               XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
 
                error = xfs_itruncate_finish(&tp, ip,
                                             ip->i_size,
@@ -909,8 +236,7 @@ xfs_free_eofblocks(
                        error = xfs_trans_commit(tp,
                                                XFS_TRANS_RELEASE_LOG_RES);
                }
-               xfs_iunlock(ip, (use_iolock ? (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)
-                                           : XFS_ILOCK_EXCL));
+               xfs_iunlock(ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL);
        }
        return error;
 }
@@ -964,18 +290,17 @@ xfs_inactive_symlink_rmt(
        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, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-       xfs_trans_ihold(tp, ip);
+       xfs_trans_ijoin(tp, ip);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        /*
         * Find the block(s) so we can inval and unmap them.
         */
        done = 0;
-       XFS_BMAP_INIT(&free_list, &first_block);
+       xfs_bmap_init(&free_list, &first_block);
        nmaps = ARRAY_SIZE(mval);
        if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size),
                        XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps,
-                       &free_list, NULL)))
+                       &free_list)))
                goto error0;
        /*
         * Invalidate the block(s).
@@ -990,7 +315,7 @@ xfs_inactive_symlink_rmt(
         * Unmap the dead block(s) to the free_list.
         */
        if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps,
-                       &first_block, &free_list, NULL, &done)))
+                       &first_block, &free_list, &done)))
                goto error1;
        ASSERT(done);
        /*
@@ -1009,8 +334,7 @@ xfs_inactive_symlink_rmt(
         * Mark it dirty so it will be logged and moved forward in the log as
         * part of every commit.
         */
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-       xfs_trans_ihold(tp, ip);
+       xfs_trans_ijoin(tp, ip);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        /*
         * Get a new, empty transaction to return to our caller.
@@ -1029,6 +353,12 @@ xfs_inactive_symlink_rmt(
                goto error0;
        }
        /*
+        * transaction commit worked ok so we can drop the extra ticket
+        * reference that we gained in xfs_trans_dup()
+        */
+       xfs_log_ticket_put(tp->t_ticket);
+
+       /*
         * Remove the memory for extent descriptions (just bookkeeping).
         */
        if (ip->i_df.if_bytes)
@@ -1137,8 +467,7 @@ xfs_inactive_attrs(
                goto error_cancel;
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
-       xfs_trans_ihold(tp, ip);
+       xfs_trans_ijoin(tp, ip);
        xfs_idestroy_fork(ip, XFS_ATTR_FORK);
 
        ASSERT(ip->i_d.di_anextents == 0);
@@ -1186,30 +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, XFS_B_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)))) {
-                       error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK);
-                       if (error)
-                               return error;
+               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)
+               return 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 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;
 }
 
@@ -1233,13 +594,11 @@ xfs_inactive(
        int             error;
        int             truncate;
 
-       xfs_itrace_entry(ip);
-
        /*
         * If the inode is already free, then there can be nothing
         * to clean up here.
         */
-       if (ip->i_d.di_mode == 0 || VN_BAD(VFS_I(ip))) {
+       if (ip->i_d.di_mode == 0 || is_bad_inode(VFS_I(ip))) {
                ASSERT(ip->i_df.if_real_bytes == 0);
                ASSERT(ip->i_df.if_broot_bytes == 0);
                return VN_INACTIVE_CACHE;
@@ -1258,9 +617,6 @@ xfs_inactive(
 
        mp = ip->i_mount;
 
-       if (ip->i_d.di_nlink == 0 && DM_EVENT_ENABLED(ip, DM_EVENT_DESTROY))
-               XFS_SEND_DESTROY(mp, ip, DM_RIGHT_NULL);
-
        error = 0;
 
        /* If this is a read-only mount, don't do this (would generate I/O) */
@@ -1275,7 +631,7 @@ xfs_inactive(
                     (!(ip->i_d.di_flags &
                                (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||
                      (ip->i_delayed_blks != 0)))) {
-                       error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK);
+                       error = xfs_free_eofblocks(mp, ip, 0);
                        if (error)
                                return VN_INACTIVE_CACHE;
                }
@@ -1284,25 +640,15 @@ xfs_inactive(
 
        ASSERT(ip->i_d.di_nlink == 0);
 
-       if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+       error = xfs_qm_dqattach(ip, 0);
+       if (error)
                return VN_INACTIVE_CACHE;
 
        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),
@@ -1317,8 +663,7 @@ xfs_inactive(
                }
 
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
 
                /*
                 * normally, we have to run xfs_itruncate_finish sync.
@@ -1351,8 +696,7 @@ xfs_inactive(
                        return VN_INACTIVE_CACHE;
                }
 
-               xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
        } else {
                error = xfs_trans_reserve(tp, 0,
                                          XFS_IFREE_LOG_RES(mp),
@@ -1365,8 +709,7 @@ xfs_inactive(
                }
 
                xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-               xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
        }
 
        /*
@@ -1391,7 +734,7 @@ xfs_inactive(
        /*
         * Free the inode.
         */
-       XFS_BMAP_INIT(&free_list, &first_block);
+       xfs_bmap_init(&free_list, &first_block);
        error = xfs_ifree(tp, ip, &free_list);
        if (error) {
                /*
@@ -1400,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);
@@ -1410,7 +752,7 @@ xfs_inactive(
                /*
                 * Credit the quota account(s). The inode is gone.
                 */
-               XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
+               xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
 
                /*
                 * Just ignore errors at this point.  There is nothing we can
@@ -1419,18 +761,18 @@ 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);
        }
+
        /*
         * Release the dquots held by inode, if any.
         */
-       XFS_QM_DQDETACH(mp, ip);
-
+       xfs_qm_dqdetach(ip);
        xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
 
  out:
@@ -1454,7 +796,7 @@ xfs_lookup(
        int                     error;
        uint                    lock_mode;
 
-       xfs_itrace_entry(dp);
+       trace_xfs_lookup(dp, name);
 
        if (XFS_FORCED_SHUTDOWN(dp->i_mount))
                return XFS_ERROR(EIO);
@@ -1466,11 +808,10 @@ xfs_lookup(
        if (error)
                goto out;
 
-       error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp, 0);
+       error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp);
        if (error)
                goto out_free_name;
 
-       xfs_itrace_ref(*ipp);
        return 0;
 
 out_free_name:
@@ -1487,113 +828,119 @@ xfs_create(
        struct xfs_name         *name,
        mode_t                  mode,
        xfs_dev_t               rdev,
-       xfs_inode_t             **ipp,
-       cred_t                  *credp)
+       xfs_inode_t             **ipp)
 {
-       xfs_mount_t             *mp = dp->i_mount;
-       xfs_inode_t             *ip;
-       xfs_trans_t             *tp;
+       int                     is_dir = S_ISDIR(mode);
+       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_inode        *ip = NULL;
+       struct xfs_trans        *tp = NULL;
        int                     error;
        xfs_bmap_free_t         free_list;
        xfs_fsblock_t           first_block;
        boolean_t               unlock_dp_on_error = B_FALSE;
-       int                     dm_event_sent = 0;
        uint                    cancel_flags;
        int                     committed;
-       xfs_prid_t              prid;
-       struct xfs_dquot        *udqp, *gdqp;
+       prid_t                  prid;
+       struct xfs_dquot        *udqp = NULL;
+       struct xfs_dquot        *gdqp = NULL;
        uint                    resblks;
+       uint                    log_res;
+       uint                    log_count;
 
-       ASSERT(!*ipp);
-       xfs_itrace_entry(dp);
-
-       if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) {
-               error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
-                               dp, DM_RIGHT_NULL, NULL,
-                               DM_RIGHT_NULL, name->name, NULL,
-                               mode, 0, 0);
-
-               if (error)
-                       return error;
-               dm_event_sent = 1;
-       }
+       trace_xfs_create(dp, name);
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
 
-       /* Return through std_return after this point. */
-
-       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.
         */
-       error = XFS_QM_DQVOPALLOC(mp, dp,
-                       current_fsuid(credp), current_fsgid(credp), prid,
-                       XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp);
+       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;
 
-       ip = NULL;
+       if (is_dir) {
+               rdev = 0;
+               resblks = XFS_MKDIR_SPACE_RES(mp, name->len);
+               log_res = XFS_MKDIR_LOG_RES(mp);
+               log_count = XFS_MKDIR_LOG_COUNT;
+               tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR);
+       } else {
+               resblks = XFS_CREATE_SPACE_RES(mp, name->len);
+               log_res = XFS_CREATE_LOG_RES(mp);
+               log_count = XFS_CREATE_LOG_COUNT;
+               tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE);
+       }
 
-       tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE);
        cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
-       resblks = XFS_CREATE_SPACE_RES(mp, name->len);
+
        /*
         * Initially assume that the file does not exist and
         * reserve the resources for that case.  If that is not
         * the case we'll drop the one we have and get a more
         * appropriate transaction later.
         */
-       error = xfs_trans_reserve(tp, resblks, XFS_CREATE_LOG_RES(mp), 0,
-                       XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT);
+       error = xfs_trans_reserve(tp, resblks, log_res, 0,
+                       XFS_TRANS_PERM_LOG_RES, log_count);
+       if (error == ENOSPC) {
+               /* flush outstanding delalloc blocks and retry */
+               xfs_flush_inodes(dp);
+               error = xfs_trans_reserve(tp, resblks, log_res, 0,
+                               XFS_TRANS_PERM_LOG_RES, log_count);
+       }
        if (error == ENOSPC) {
+               /* No space at all so try a "no-allocation" reservation */
                resblks = 0;
-               error = xfs_trans_reserve(tp, 0, XFS_CREATE_LOG_RES(mp), 0,
-                               XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT);
+               error = xfs_trans_reserve(tp, 0, log_res, 0,
+                               XFS_TRANS_PERM_LOG_RES, log_count);
        }
        if (error) {
                cancel_flags = 0;
-               goto error_return;
+               goto out_trans_cancel;
        }
 
        xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
        unlock_dp_on_error = B_TRUE;
 
-       XFS_BMAP_INIT(&free_list, &first_block);
+       /*
+        * Check for directory link count overflow.
+        */
+       if (is_dir && dp->i_d.di_nlink >= XFS_MAXLINK) {
+               error = XFS_ERROR(EMLINK);
+               goto out_trans_cancel;
+       }
 
-       ASSERT(ip == NULL);
+       xfs_bmap_init(&free_list, &first_block);
 
        /*
         * Reserve disk quota and the inode.
         */
-       error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
+       error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
        if (error)
-               goto error_return;
+               goto out_trans_cancel;
 
        error = xfs_dir_canenter(tp, dp, name, resblks);
        if (error)
-               goto error_return;
-       error = xfs_dir_ialloc(&tp, dp, mode, 1,
-                       rdev, credp, prid, resblks > 0,
-                       &ip, &committed);
-       if (error) {
-               if (error == ENOSPC)
-                       goto error_return;
-               goto abort_return;
-       }
-       xfs_itrace_ref(ip);
+               goto out_trans_cancel;
 
        /*
-        * At this point, we've gotten a newly allocated inode.
-        * It is locked (and joined to the transaction).
+        * A newly created regular or special file just has one directory
+        * entry pointing to them, but a directory also the "." entry
+        * pointing to itself.
         */
-
-       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+       error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev,
+                              prid, resblks > 0, &ip, &committed);
+       if (error) {
+               if (error == ENOSPC)
+                       goto out_trans_cancel;
+               goto out_trans_abort;
+       }
 
        /*
         * Now we join the directory inode to the transaction.  We do not do it
@@ -1602,8 +949,7 @@ xfs_create(
         * the transaction cancel unlocking dp so don't do it explicitly in the
         * error path.
         */
-       IHOLD(dp);
-       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
        unlock_dp_on_error = B_FALSE;
 
        error = xfs_dir_createname(tp, dp, name, ip->i_ino,
@@ -1611,97 +957,71 @@ xfs_create(
                                        resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
        if (error) {
                ASSERT(error != ENOSPC);
-               goto abort_return;
+               goto out_trans_abort;
        }
-       xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+       xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
        xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
 
+       if (is_dir) {
+               error = xfs_dir_init(tp, ip, dp);
+               if (error)
+                       goto out_bmap_cancel;
+
+               error = xfs_bumplink(tp, dp);
+               if (error)
+                       goto out_bmap_cancel;
+       }
+
        /*
         * If this is a synchronous mount, make sure that the
         * create transaction goes to disk before returning to
         * the user.
         */
-       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
+       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
                xfs_trans_set_sync(tp);
-       }
-
-       dp->i_gen++;
 
        /*
         * Attach the dquot(s) to the inodes and modify them incore.
         * These ids of the inode couldn't have changed since the new
         * inode has been locked ever since it was created.
         */
-       XFS_QM_DQVOPCREATE(mp, 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);
+       xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
 
        error = xfs_bmap_finish(&tp, &free_list, &committed);
-       if (error) {
-               xfs_bmap_cancel(&free_list);
-               goto abort_rele;
-       }
+       if (error)
+               goto out_bmap_cancel;
 
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       if (error) {
-               IRELE(ip);
-               tp = NULL;
-               goto error_return;
-       }
+       if (error)
+               goto out_release_inode;
 
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
 
        *ipp = ip;
+       return 0;
 
-       /* Fallthrough to std_return with error = 0  */
-
-std_return:
-       if ((*ipp || (error != 0 && dm_event_sent != 0)) &&
-           DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) {
-               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE,
-                       dp, DM_RIGHT_NULL,
-                       *ipp ? ip : NULL,
-                       DM_RIGHT_NULL, name->name, NULL,
-                       mode, error, 0);
-       }
-       return error;
-
- abort_return:
+ out_bmap_cancel:
+       xfs_bmap_cancel(&free_list);
+ out_trans_abort:
        cancel_flags |= XFS_TRANS_ABORT;
-       /* FALLTHROUGH */
-
- error_return:
-       if (tp != NULL)
-               xfs_trans_cancel(tp, cancel_flags);
-
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
-
-       if (unlock_dp_on_error)
-               xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
-       goto std_return;
-
- abort_rele:
+ out_trans_cancel:
+       xfs_trans_cancel(tp, cancel_flags);
+ out_release_inode:
        /*
         * Wait until after the current transaction is aborted to
         * release the inode.  This prevents recursive transactions
         * and deadlocks from xfs_inactive.
         */
-       cancel_flags |= XFS_TRANS_ABORT;
-       xfs_trans_cancel(tp, cancel_flags);
-       IRELE(ip);
+       if (ip)
+               IRELE(ip);
 
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
 
-       goto std_return;
+       if (unlock_dp_on_error)
+               xfs_iunlock(dp, XFS_ILOCK_EXCL);
+       return error;
 }
 
 #ifdef DEBUG
@@ -1838,6 +1158,12 @@ again:
 #endif
 }
 
+/*
+ * xfs_lock_two_inodes() can only be used to lock one type of lock
+ * at a time - the iolock or the ilock, but not both at once. If
+ * we lock both at once, lockdep will report false positives saying
+ * we have violated locking orders.
+ */
 void
 xfs_lock_two_inodes(
        xfs_inode_t             *ip0,
@@ -1848,6 +1174,8 @@ xfs_lock_two_inodes(
        int                     attempts = 0;
        xfs_log_item_t          *lp;
 
+       if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
+               ASSERT((lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)) == 0);
        ASSERT(ip0->i_ino != ip1->i_ino);
 
        if (ip0->i_ino > ip1->i_ino) {
@@ -1895,25 +1223,16 @@ xfs_remove(
        uint                    resblks;
        uint                    log_count;
 
-       xfs_itrace_entry(dp);
-       xfs_itrace_entry(ip);
+       trace_xfs_remove(dp, name);
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
 
-       if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) {
-               error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, dp, DM_RIGHT_NULL,
-                                       NULL, DM_RIGHT_NULL, name->name, NULL,
-                                       ip->i_d.di_mode, 0, 0);
-               if (error)
-                       return error;
-       }
-
-       error = XFS_QM_DQATTACH(mp, dp, 0);
+       error = xfs_qm_dqattach(dp, 0);
        if (error)
                goto std_return;
 
-       error = XFS_QM_DQATTACH(mp, ip, 0);
+       error = xfs_qm_dqattach(ip, 0);
        if (error)
                goto std_return;
 
@@ -1951,15 +1270,8 @@ xfs_remove(
 
        xfs_lock_two_inodes(dp, ip, XFS_ILOCK_EXCL);
 
-       /*
-        * At this point, we've gotten both the directory and the entry
-        * inodes locked.
-        */
-       IHOLD(ip);
-       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
-
-       IHOLD(dp);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
 
        /*
         * If we're removing a directory perform some additional validation.
@@ -1976,21 +1288,14 @@ xfs_remove(
                }
        }
 
-       XFS_BMAP_INIT(&free_list, &first_block);
+       xfs_bmap_init(&free_list, &first_block);
        error = xfs_dir_removename(tp, dp, name, ip->i_ino,
                                        &first_block, &free_list, resblks);
        if (error) {
                ASSERT(error != ENOENT);
                goto out_bmap_cancel;
        }
-       xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-
-       /*
-        * Bump the in memory generation count on the parent
-        * directory so that other can know that it has changed.
-        */
-       dp->i_gen++;
-       xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
+       xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 
        if (is_dir) {
                /*
@@ -2001,7 +1306,7 @@ xfs_remove(
                        goto out_bmap_cancel;
 
                /*
-                * Drop the link from dp to ip.
+                * Drop the "." link from ip to self.
                 */
                error = xfs_droplink(tp, ip);
                if (error)
@@ -2009,14 +1314,14 @@ xfs_remove(
        } else {
                /*
                 * When removing a non-directory we need to log the parent
-                * inode here for the i_gen update.  For a directory this is
-                * done implicitly by the xfs_droplink call for the ".." entry.
+                * inode here.  For a directory this is done implicitly
+                * by the xfs_droplink call for the ".." entry.
                 */
                xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
        }
 
        /*
-        * Drop the "." link from ip to self.
+        * Drop the link from dp to ip.
         */
        error = xfs_droplink(tp, ip);
        if (error)
@@ -2053,24 +1358,15 @@ xfs_remove(
        if (!is_dir && link_zero && xfs_inode_is_filestream(ip))
                xfs_filestream_deassociate(ip);
 
-       xfs_itrace_exit(ip);
-       xfs_itrace_exit(dp);
-
- std_return:
-       if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) {
-               XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, dp, DM_RIGHT_NULL,
-                               NULL, DM_RIGHT_NULL, name->name, NULL,
-                               ip->i_d.di_mode, error, 0);
-       }
-
-       return error;
+       return 0;
 
  out_bmap_cancel:
        xfs_bmap_cancel(&free_list);
        cancel_flags |= XFS_TRANS_ABORT;
  out_trans_cancel:
        xfs_trans_cancel(tp, cancel_flags);
-       goto std_return;
+ std_return:
+       return error;
 }
 
 int
@@ -2088,28 +1384,18 @@ xfs_link(
        int                     committed;
        int                     resblks;
 
-       xfs_itrace_entry(tdp);
-       xfs_itrace_entry(sip);
+       trace_xfs_link(tdp, target_name);
 
        ASSERT(!S_ISDIR(sip->i_d.di_mode));
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
 
-       if (DM_EVENT_ENABLED(tdp, DM_EVENT_LINK)) {
-               error = XFS_SEND_NAMESP(mp, DM_EVENT_LINK,
-                                       tdp, DM_RIGHT_NULL,
-                                       sip, DM_RIGHT_NULL,
-                                       target_name->name, NULL, 0, 0, 0);
-               if (error)
-                       return error;
-       }
-
-       /* Return through std_return after this point. */
+       error = xfs_qm_dqattach(sip, 0);
+       if (error)
+               goto std_return;
 
-       error = XFS_QM_DQATTACH(mp, sip, 0);
-       if (!error && sip != tdp)
-               error = XFS_QM_DQATTACH(mp, tdp, 0);
+       error = xfs_qm_dqattach(tdp, 0);
        if (error)
                goto std_return;
 
@@ -2130,15 +1416,8 @@ xfs_link(
 
        xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL);
 
-       /*
-        * Increment vnode ref counts since xfs_trans_commit &
-        * xfs_trans_cancel will both unlock the inodes and
-        * decrement the associated ref counts.
-        */
-       IHOLD(sip);
-       IHOLD(tdp);
-       xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, sip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, tdp, XFS_ILOCK_EXCL);
 
        /*
         * If the source has too many links, we can't make any more to it.
@@ -2154,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;
        }
@@ -2163,14 +1442,13 @@ xfs_link(
        if (error)
                goto error_return;
 
-       XFS_BMAP_INIT(&free_list, &first_block);
+       xfs_bmap_init(&free_list, &first_block);
 
        error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
                                        &first_block, &free_list, resblks);
        if (error)
                goto abort_return;
-       xfs_ichgtime(tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-       tdp->i_gen++;
+       xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
        xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
 
        error = xfs_bumplink(tp, sip);
@@ -2192,238 +1470,14 @@ xfs_link(
                goto abort_return;
        }
 
-       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       if (error)
-               goto std_return;
-
-       /* Fall through to std_return with error = 0. */
-std_return:
-       if (DM_EVENT_ENABLED(sip, DM_EVENT_POSTLINK)) {
-               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTLINK,
-                               tdp, DM_RIGHT_NULL,
-                               sip, DM_RIGHT_NULL,
-                               target_name->name, NULL, 0, error, 0);
-       }
-       return error;
+       return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 
  abort_return:
        cancel_flags |= XFS_TRANS_ABORT;
-       /* FALLTHROUGH */
-
  error_return:
        xfs_trans_cancel(tp, cancel_flags);
-       goto std_return;
-}
-
-
-int
-xfs_mkdir(
-       xfs_inode_t             *dp,
-       struct xfs_name         *dir_name,
-       mode_t                  mode,
-       xfs_inode_t             **ipp,
-       cred_t                  *credp)
-{
-       xfs_mount_t             *mp = dp->i_mount;
-       xfs_inode_t             *cdp;   /* inode of created dir */
-       xfs_trans_t             *tp;
-       int                     cancel_flags;
-       int                     error;
-       int                     committed;
-       xfs_bmap_free_t         free_list;
-       xfs_fsblock_t           first_block;
-       boolean_t               unlock_dp_on_error = B_FALSE;
-       boolean_t               created = B_FALSE;
-       int                     dm_event_sent = 0;
-       xfs_prid_t              prid;
-       struct xfs_dquot        *udqp, *gdqp;
-       uint                    resblks;
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
-
-       tp = NULL;
-
-       if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) {
-               error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
-                                       dp, DM_RIGHT_NULL, NULL,
-                                       DM_RIGHT_NULL, dir_name->name, NULL,
-                                       mode, 0, 0);
-               if (error)
-                       return error;
-               dm_event_sent = 1;
-       }
-
-       /* Return through std_return after this point. */
-
-       xfs_itrace_entry(dp);
-
-       mp = dp->i_mount;
-       udqp = gdqp = NULL;
-       if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
-               prid = dp->i_d.di_projid;
-       else
-               prid = (xfs_prid_t)dfltprid;
-
-       /*
-        * Make sure that we have allocated dquot(s) on disk.
-        */
-       error = XFS_QM_DQVOPALLOC(mp, dp,
-                       current_fsuid(credp), current_fsgid(credp), prid,
-                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
-       if (error)
-               goto std_return;
-
-       tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR);
-       cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
-       resblks = XFS_MKDIR_SPACE_RES(mp, dir_name->len);
-       error = xfs_trans_reserve(tp, resblks, XFS_MKDIR_LOG_RES(mp), 0,
-                                 XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT);
-       if (error == ENOSPC) {
-               resblks = 0;
-               error = xfs_trans_reserve(tp, 0, XFS_MKDIR_LOG_RES(mp), 0,
-                                         XFS_TRANS_PERM_LOG_RES,
-                                         XFS_MKDIR_LOG_COUNT);
-       }
-       if (error) {
-               cancel_flags = 0;
-               goto error_return;
-       }
-
-       xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
-       unlock_dp_on_error = B_TRUE;
-
-       /*
-        * Check for directory link count overflow.
-        */
-       if (dp->i_d.di_nlink >= XFS_MAXLINK) {
-               error = XFS_ERROR(EMLINK);
-               goto error_return;
-       }
-
-       /*
-        * Reserve disk quota and the inode.
-        */
-       error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
-       if (error)
-               goto error_return;
-
-       error = xfs_dir_canenter(tp, dp, dir_name, resblks);
-       if (error)
-               goto error_return;
-       /*
-        * create the directory inode.
-        */
-       error = xfs_dir_ialloc(&tp, dp, mode, 2,
-                       0, credp, prid, resblks > 0,
-               &cdp, NULL);
-       if (error) {
-               if (error == ENOSPC)
-                       goto error_return;
-               goto abort_return;
-       }
-       xfs_itrace_ref(cdp);
-
-       /*
-        * Now we add the directory inode to the transaction.
-        * We waited until now since xfs_dir_ialloc might start
-        * a new transaction.  Had we joined the transaction
-        * earlier, the locks might have gotten released. An error
-        * from here on will result in the transaction cancel
-        * unlocking dp so don't do it explicitly in the error path.
-        */
-       IHOLD(dp);
-       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
-       unlock_dp_on_error = B_FALSE;
-
-       XFS_BMAP_INIT(&free_list, &first_block);
-
-       error = xfs_dir_createname(tp, dp, dir_name, cdp->i_ino,
-                                       &first_block, &free_list, resblks ?
-                                       resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
-       if (error) {
-               ASSERT(error != ENOSPC);
-               goto error1;
-       }
-       xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-
-       /*
-        * Bump the in memory version number of the parent directory
-        * so that other processes accessing it will recognize that
-        * the directory has changed.
-        */
-       dp->i_gen++;
-
-       error = xfs_dir_init(tp, cdp, dp);
-       if (error)
-               goto error2;
-
-       cdp->i_gen = 1;
-       error = xfs_bumplink(tp, dp);
-       if (error)
-               goto error2;
-
-       created = B_TRUE;
-
-       *ipp = cdp;
-       IHOLD(cdp);
-
-       /*
-        * Attach the dquots to the new inode and modify the icount incore.
-        */
-       XFS_QM_DQVOPCREATE(mp, tp, cdp, udqp, gdqp);
-
-       /*
-        * If this is a synchronous mount, make sure that the
-        * mkdir transaction goes to disk before returning to
-        * the user.
-        */
-       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
-               xfs_trans_set_sync(tp);
-       }
-
-       error = xfs_bmap_finish(&tp, &free_list, &committed);
-       if (error) {
-               IRELE(cdp);
-               goto error2;
-       }
-
-       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
-       if (error) {
-               IRELE(cdp);
-       }
-
-       /* Fall through to std_return with error = 0 or errno from
-        * xfs_trans_commit. */
-
-std_return:
-       if ((created || (error != 0 && dm_event_sent != 0)) &&
-           DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) {
-               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE,
-                                       dp, DM_RIGHT_NULL,
-                                       created ? cdp : NULL,
-                                       DM_RIGHT_NULL,
-                                       dir_name->name, NULL,
-                                       mode, error, 0);
-       }
+ std_return:
        return error;
-
- error2:
- error1:
-       xfs_bmap_cancel(&free_list);
- abort_return:
-       cancel_flags |= XFS_TRANS_ABORT;
- error_return:
-       xfs_trans_cancel(tp, cancel_flags);
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
-
-       if (unlock_dp_on_error)
-               xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
-       goto std_return;
 }
 
 int
@@ -2432,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;
@@ -2454,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;
 
@@ -2463,7 +1516,7 @@ xfs_symlink(
        ip = NULL;
        tp = NULL;
 
-       xfs_itrace_entry(dp);
+       trace_xfs_symlink(dp, link_name);
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
@@ -2475,27 +1528,16 @@ xfs_symlink(
        if (pathlen >= MAXPATHLEN)      /* total string too long */
                return XFS_ERROR(ENAMETOOLONG);
 
-       if (DM_EVENT_ENABLED(dp, DM_EVENT_SYMLINK)) {
-               error = XFS_SEND_NAMESP(mp, DM_EVENT_SYMLINK, dp,
-                                       DM_RIGHT_NULL, NULL, DM_RIGHT_NULL,
-                                       link_name->name, target_path, 0, 0, 0);
-               if (error)
-                       return error;
-       }
-
-       /* Return through std_return after this point. */
-
        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.
         */
-       error = XFS_QM_DQVOPALLOC(mp, dp,
-                       current_fsuid(credp), current_fsgid(credp), prid,
+       error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
                        XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
        if (error)
                goto std_return;
@@ -2537,7 +1579,7 @@ xfs_symlink(
        /*
         * Reserve disk quota : blocks and inode.
         */
-       error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
+       error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
        if (error)
                goto error_return;
 
@@ -2551,33 +1593,31 @@ xfs_symlink(
         * Initialize the bmap freelist prior to calling either
         * bmapi or the directory create code.
         */
-       XFS_BMAP_INIT(&free_list, &first_block);
+       xfs_bmap_init(&free_list, &first_block);
 
        /*
         * 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;
                goto error1;
        }
-       xfs_itrace_ref(ip);
 
        /*
         * An error after we've joined dp to the transaction will result in the
         * transaction cancel unlocking dp so don't do it explicitly in the
         * error path.
         */
-       IHOLD(dp);
-       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
        unlock_dp_on_error = B_FALSE;
 
        /*
         * Also attach the dquot(s) to it, if applicable.
         */
-       XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp);
+       xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
 
        if (resblks)
                resblks -= XFS_IALLOC_SPACE_RES(mp);
@@ -2605,10 +1645,9 @@ xfs_symlink(
                error = xfs_bmapi(tp, ip, first_fsb, fs_blocks,
                                  XFS_BMAPI_WRITE | XFS_BMAPI_METADATA,
                                  &first_block, resblks, mval, &nmaps,
-                                 &free_list, NULL);
-               if (error) {
-                       goto error1;
-               }
+                                 &free_list);
+               if (error)
+                       goto error2;
 
                if (resblks)
                        resblks -= fs_blocks;
@@ -2640,18 +1679,11 @@ xfs_symlink(
        error = xfs_dir_createname(tp, dp, link_name, ip->i_ino,
                                        &first_block, &free_list, resblks);
        if (error)
-               goto error1;
-       xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+               goto error2;
+       xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
        xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
 
        /*
-        * Bump the in memory version number of the parent directory
-        * so that other processes accessing it will recognize that
-        * the directory has changed.
-        */
-       dp->i_gen++;
-
-       /*
         * If this is a synchronous mount, make sure that the
         * symlink transaction goes to disk before returning to
         * the user.
@@ -2660,35 +1692,16 @@ 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;
        }
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
-
-       /* Fall through to std_return with error = 0 or errno from
-        * xfs_trans_commit     */
-std_return:
-       if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTSYMLINK)) {
-               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTSYMLINK,
-                                       dp, DM_RIGHT_NULL,
-                                       error ? NULL : ip,
-                                       DM_RIGHT_NULL, link_name->name,
-                                       target_path, 0, error, 0);
-       }
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
 
-       if (!error)
-               *ipp = ip;
-       return error;
+       *ipp = ip;
+       return 0;
 
  error2:
        IRELE(ip);
@@ -2697,60 +1710,15 @@ std_return:
        cancel_flags |= XFS_TRANS_ABORT;
  error_return:
        xfs_trans_cancel(tp, cancel_flags);
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
 
        if (unlock_dp_on_error)
                xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
-       goto std_return;
-}
-
-int
-xfs_inode_flush(
-       xfs_inode_t     *ip,
-       int             flags)
-{
-       xfs_mount_t     *mp = ip->i_mount;
-       int             error = 0;
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
-
-       /*
-        * Bypass inodes which have already been cleaned by
-        * the inode flush clustering code inside xfs_iflush
-        */
-       if (xfs_inode_clean(ip))
-               return 0;
-
-       /*
-        * We make this non-blocking if the inode is contended,
-        * return EAGAIN to indicate to the caller that they
-        * did not succeed. This prevents the flush path from
-        * blocking on inodes inside another operation right
-        * now, they get caught later by xfs_sync.
-        */
-       if (flags & FLUSH_SYNC) {
-               xfs_ilock(ip, XFS_ILOCK_SHARED);
-               xfs_iflock(ip);
-       } else if (xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) {
-               if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip)) {
-                       xfs_iunlock(ip, XFS_ILOCK_SHARED);
-                       return EAGAIN;
-               }
-       } else {
-               return EAGAIN;
-       }
-
-       error = xfs_iflush(ip, (flags & FLUSH_SYNC) ? XFS_IFLUSH_SYNC
-                                                   : XFS_IFLUSH_ASYNC_NOBLOCK);
-       xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
+ std_return:
        return error;
 }
 
-
 int
 xfs_set_dmattrs(
        xfs_inode_t     *ip,
@@ -2774,176 +1742,17 @@ xfs_set_dmattrs(
                return error;
        }
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
 
        ip->i_d.di_dmevmask = evmask;
        ip->i_d.di_dmstate  = state;
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-       IHOLD(ip);
        error = xfs_trans_commit(tp, 0);
 
        return error;
 }
 
-int
-xfs_reclaim(
-       xfs_inode_t     *ip)
-{
-
-       xfs_itrace_entry(ip);
-
-       ASSERT(!VN_MAPPED(VFS_I(ip)));
-
-       /* bad inode, get out here ASAP */
-       if (VN_BAD(VFS_I(ip))) {
-               xfs_ireclaim(ip);
-               return 0;
-       }
-
-       vn_iowait(ip);
-
-       ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0);
-
-       /*
-        * Make sure the atime in the XFS inode is correct before freeing the
-        * Linux inode.
-        */
-       xfs_synchronize_atime(ip);
-
-       /*
-        * If we have nothing to flush with this inode then complete the
-        * teardown now, otherwise break the link between the xfs inode and the
-        * linux inode and clean up the xfs inode later. This avoids flushing
-        * the inode to disk during the delete operation itself.
-        *
-        * When breaking the link, we need to set the XFS_IRECLAIMABLE flag
-        * first to ensure that xfs_iunpin() will never see an xfs inode
-        * that has a linux inode being reclaimed. Synchronisation is provided
-        * by the i_flags_lock.
-        */
-       if (!ip->i_update_core && (ip->i_itemp == NULL)) {
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_iflock(ip);
-               return xfs_finish_reclaim(ip, 1, XFS_IFLUSH_DELWRI_ELSE_SYNC);
-       } else {
-               xfs_mount_t     *mp = ip->i_mount;
-
-               /* Protect sync and unpin from us */
-               XFS_MOUNT_ILOCK(mp);
-               spin_lock(&ip->i_flags_lock);
-               __xfs_iflags_set(ip, XFS_IRECLAIMABLE);
-               VFS_I(ip)->i_private = NULL;
-               ip->i_vnode = NULL;
-               spin_unlock(&ip->i_flags_lock);
-               list_add_tail(&ip->i_reclaim, &mp->m_del_inodes);
-               XFS_MOUNT_IUNLOCK(mp);
-       }
-       return 0;
-}
-
-int
-xfs_finish_reclaim(
-       xfs_inode_t     *ip,
-       int             locked,
-       int             sync_mode)
-{
-       xfs_perag_t     *pag = xfs_get_perag(ip->i_mount, ip->i_ino);
-       struct inode    *vp = VFS_I(ip);
-
-       if (vp && VN_BAD(vp))
-               goto reclaim;
-
-       /* The hash lock here protects a thread in xfs_iget_core from
-        * racing with us on linking the inode back with a vnode.
-        * Once we have the XFS_IRECLAIM flag set it will not touch
-        * us.
-        */
-       write_lock(&pag->pag_ici_lock);
-       spin_lock(&ip->i_flags_lock);
-       if (__xfs_iflags_test(ip, XFS_IRECLAIM) ||
-           (!__xfs_iflags_test(ip, XFS_IRECLAIMABLE) && vp == NULL)) {
-               spin_unlock(&ip->i_flags_lock);
-               write_unlock(&pag->pag_ici_lock);
-               if (locked) {
-                       xfs_ifunlock(ip);
-                       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-               }
-               return 1;
-       }
-       __xfs_iflags_set(ip, XFS_IRECLAIM);
-       spin_unlock(&ip->i_flags_lock);
-       write_unlock(&pag->pag_ici_lock);
-       xfs_put_perag(ip->i_mount, pag);
-
-       /*
-        * If the inode is still dirty, then flush it out.  If the inode
-        * is not in the AIL, then it will be OK to flush it delwri as
-        * long as xfs_iflush() does not keep any references to the inode.
-        * We leave that decision up to xfs_iflush() since it has the
-        * knowledge of whether it's OK to simply do a delwri flush of
-        * the inode or whether we need to wait until the inode is
-        * pulled from the AIL.
-        * We get the flush lock regardless, though, just to make sure
-        * we don't free it while it is being flushed.
-        */
-       if (!locked) {
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_iflock(ip);
-       }
-
-       /*
-        * In the case of a forced shutdown we rely on xfs_iflush() to
-        * wait for the inode to be unpinned before returning an error.
-        */
-       if (xfs_iflush(ip, sync_mode) == 0) {
-               /* synchronize with xfs_iflush_done */
-               xfs_iflock(ip);
-               xfs_ifunlock(ip);
-       }
-
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-
- reclaim:
-       xfs_ireclaim(ip);
-       return 0;
-}
-
-int
-xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock)
-{
-       int             purged;
-       xfs_inode_t     *ip, *n;
-       int             done = 0;
-
-       while (!done) {
-               purged = 0;
-               XFS_MOUNT_ILOCK(mp);
-               list_for_each_entry_safe(ip, n, &mp->m_del_inodes, i_reclaim) {
-                       if (noblock) {
-                               if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0)
-                                       continue;
-                               if (xfs_ipincount(ip) ||
-                                   !xfs_iflock_nowait(ip)) {
-                                       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-                                       continue;
-                               }
-                       }
-                       XFS_MOUNT_IUNLOCK(mp);
-                       if (xfs_finish_reclaim(ip, noblock,
-                                       XFS_IFLUSH_DELWRI_ELSE_ASYNC))
-                               delay(1);
-                       purged = 1;
-                       break;
-               }
-
-               done = !purged;
-       }
-
-       XFS_MOUNT_IUNLOCK(mp);
-       return 0;
-}
-
 /*
  * xfs_alloc_file_space()
  *      This routine allocates disk space for the given file.
@@ -2989,12 +1798,13 @@ xfs_alloc_file_space(
        int                     committed;
        int                     error;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_alloc_file_space(ip);
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
 
-       if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+       error = xfs_qm_dqattach(ip, 0);
+       if (error)
                return error;
 
        if (len <= 0)
@@ -3006,29 +1816,13 @@ xfs_alloc_file_space(
        count = len;
        imapp = &imaps[0];
        nimaps = 1;
-       bmapi_flag = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0);
+       bmapi_flag = XFS_BMAPI_WRITE | alloc_type;
        startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
        allocatesize_fsb = XFS_B_TO_FSB(mp, count);
 
-       /*      Generate a DMAPI event if needed.       */
-       if (alloc_type != 0 && offset < ip->i_size &&
-                       (attr_flags & XFS_ATTR_DMI) == 0  &&
-                       DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) {
-               xfs_off_t           end_dmi_offset;
-
-               end_dmi_offset = offset+len;
-               if (end_dmi_offset > ip->i_size)
-                       end_dmi_offset = ip->i_size;
-               error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, ip, offset,
-                                     end_dmi_offset - offset, 0, NULL);
-               if (error)
-                       return error;
-       }
-
        /*
         * Allocate file space until done or until there is an error
         */
-retry:
        while (allocatesize_fsb && !error) {
                xfs_fileoff_t   s, e;
 
@@ -3049,15 +1843,22 @@ retry:
                        e = allocatesize_fsb;
                }
 
+               /*
+                * The transaction reservation is limited to a 32-bit block
+                * count, hence we need to limit the number of blocks we are
+                * trying to reserve to avoid an overflow. We can't allocate
+                * more than @nimaps extents, and an extent is limited on disk
+                * to MAXEXTLEN (21 bits), so use that to enforce the limit.
+                */
+               resblks = min_t(xfs_fileoff_t, (e - s), (MAXEXTLEN * nimaps));
                if (unlikely(rt)) {
-                       resrtextents = qblocks = (uint)(e - s);
+                       resrtextents = qblocks = resblks;
                        resrtextents /= mp->m_sb.sb_rextsize;
                        resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
                        quota_flag = XFS_QMOPT_RES_RTBLKS;
                } else {
                        resrtextents = 0;
-                       resblks = qblocks = \
-                               XFS_DIOSTRAT_SPACE_RES(mp, (uint)(e - s));
+                       resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resblks);
                        quota_flag = XFS_QMOPT_RES_REGBLKS;
                }
 
@@ -3081,22 +1882,21 @@ retry:
                        break;
                }
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip,
-                                                     qblocks, 0, quota_flag);
+               error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks,
+                                                     0, quota_flag);
                if (error)
                        goto error1;
 
-               xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
 
                /*
                 * Issue the xfs_bmapi() call to allocate the blocks
                 */
-               XFS_BMAP_INIT(&free_list, &firstfsb);
+               xfs_bmap_init(&free_list, &firstfsb);
                error = xfs_bmapi(tp, ip, startoffset_fsb,
                                  allocatesize_fsb, bmapi_flag,
                                  &firstfsb, 0, imapp, &nimaps,
-                                 &free_list, NULL);
+                                 &free_list);
                if (error) {
                        goto error0;
                }
@@ -3125,33 +1925,29 @@ retry:
                startoffset_fsb += allocated_fsb;
                allocatesize_fsb -= allocated_fsb;
        }
-dmapi_enospc_check:
-       if (error == ENOSPC && (attr_flags & XFS_ATTR_DMI) == 0 &&
-           DM_EVENT_ENABLED(ip, DM_EVENT_NOSPACE)) {
-               error = XFS_SEND_NAMESP(mp, DM_EVENT_NOSPACE,
-                               ip, DM_RIGHT_NULL,
-                               ip, DM_RIGHT_NULL,
-                               NULL, NULL, 0, 0, 0); /* Delay flag intentionally unused */
-               if (error == 0)
-                       goto retry;     /* Maybe DMAPI app. has made space */
-               /* else fall through with error from XFS_SEND_DATA */
-       }
 
        return error;
 
 error0:        /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
        xfs_bmap_cancel(&free_list);
-       XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag);
+       xfs_trans_unreserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
 
 error1:        /* Just cancel transaction */
        xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       goto dmapi_enospc_check;
+       return error;
 }
 
 /*
  * Zero file bytes between startoff and endoff inclusive.
  * The iolock is held exclusive and no blocks are buffered.
+ *
+ * This function is used by xfs_free_file_space() to zero
+ * partial blocks when the range to free is not block aligned.
+ * When unreserving space with boundaries that are not block
+ * aligned we round up the start and round down the end
+ * boundaries and then use this function to zero the parts of
+ * the blocks that got dropped during the rounding.
  */
 STATIC int
 xfs_zero_remaining_bytes(
@@ -3168,15 +1964,28 @@ xfs_zero_remaining_bytes(
        int                     nimap;
        int                     error = 0;
 
-       bp = xfs_buf_get_noaddr(mp->m_sb.sb_blocksize,
-                               XFS_IS_REALTIME_INODE(ip) ?
-                               mp->m_rtdev_targp : mp->m_ddev_targp);
+       /*
+        * Avoid doing I/O beyond eof - it's not necessary
+        * since nothing can read beyond eof.  The space will
+        * be zeroed when the file is extended anyway.
+        */
+       if (startoff >= ip->i_size)
+               return 0;
+
+       if (endoff > ip->i_size)
+               endoff = ip->i_size;
+
+       bp = xfs_buf_get_uncached(XFS_IS_REALTIME_INODE(ip) ?
+                                       mp->m_rtdev_targp : mp->m_ddev_targp,
+                               mp->m_sb.sb_blocksize, XBF_DONT_BLOCK);
+       if (!bp)
+               return XFS_ERROR(ENOMEM);
 
        for (offset = startoff; offset <= endoff; offset = lastoffset + 1) {
                offset_fsb = XFS_B_TO_FSBT(mp, offset);
                nimap = 1;
                error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0,
-                       NULL, 0, &imap, &nimap, NULL, NULL);
+                       NULL, 0, &imap, &nimap, NULL);
                if (error || nimap < 1)
                        break;
                ASSERT(imap.br_blockcount >= 1);
@@ -3192,9 +2001,9 @@ xfs_zero_remaining_bytes(
                XFS_BUF_UNDONE(bp);
                XFS_BUF_UNWRITE(bp);
                XFS_BUF_READ(bp);
-               XFS_BUF_SET_ADDR(bp, XFS_FSB_TO_DB(ip, imap.br_startblock));
+               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));
@@ -3207,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));
@@ -3239,7 +2048,6 @@ xfs_free_file_space(
 {
        int                     committed;
        int                     done;
-       xfs_off_t               end_dmi_offset;
        xfs_fileoff_t           endoffset_fsb;
        int                     error;
        xfs_fsblock_t           firstfsb;
@@ -3258,9 +2066,10 @@ xfs_free_file_space(
 
        mp = ip->i_mount;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_free_file_space(ip);
 
-       if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+       error = xfs_qm_dqattach(ip, 0);
+       if (error)
                return error;
 
        error = 0;
@@ -3268,32 +2077,20 @@ xfs_free_file_space(
                return error;
        rt = XFS_IS_REALTIME_INODE(ip);
        startoffset_fsb = XFS_B_TO_FSB(mp, offset);
-       end_dmi_offset = offset + len;
-       endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset);
-
-       if (offset < ip->i_size && (attr_flags & XFS_ATTR_DMI) == 0 &&
-           DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) {
-               if (end_dmi_offset > ip->i_size)
-                       end_dmi_offset = ip->i_size;
-               error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, ip,
-                               offset, end_dmi_offset - offset,
-                               AT_DELAY_FLAG(attr_flags), NULL);
-               if (error)
-                       return error;
-       }
+       endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);
 
        if (attr_flags & XFS_ATTR_NOLOCK)
                need_iolock = 0;
        if (need_iolock) {
                xfs_ilock(ip, XFS_IOLOCK_EXCL);
-               vn_iowait(ip);  /* wait for the completion of any pending DIOs */
+               /* wait for the completion of any pending DIOs */
+               xfs_ioend_wait(ip);
        }
 
        rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE);
        ioffset = offset & ~(rounding - 1);
 
        if (VN_CACHED(VFS_I(ip)) != 0) {
-               xfs_inval_cached_trace(ip, ioffset, -1, ioffset, -1);
                error = xfs_flushinval_pages(ip, ioffset, -1, FI_REMAPF_LOCKED);
                if (error)
                        goto out_unlock_iolock;
@@ -3301,14 +2098,14 @@ xfs_free_file_space(
 
        /*
         * Need to zero the stuff we're not freeing, on disk.
-        * If its a realtime file & can't use unwritten extents then we
+        * If it's a realtime file & can't use unwritten extents then we
         * actually need to zero the extent edges.  Otherwise xfs_bunmapi
         * will take care of it for us.
         */
        if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) {
                nimap = 1;
                error = xfs_bmapi(NULL, ip, startoffset_fsb,
-                       1, 0, NULL, 0, &imap, &nimap, NULL, NULL);
+                       1, 0, NULL, 0, &imap, &nimap, NULL);
                if (error)
                        goto out_unlock_iolock;
                ASSERT(nimap == 0 || nimap == 1);
@@ -3323,7 +2120,7 @@ xfs_free_file_space(
                }
                nimap = 1;
                error = xfs_bmapi(NULL, ip, endoffset_fsb - 1,
-                       1, 0, NULL, 0, &imap, &nimap, NULL, NULL);
+                       1, 0, NULL, 0, &imap, &nimap, NULL);
                if (error)
                        goto out_unlock_iolock;
                ASSERT(nimap == 0 || nimap == 1);
@@ -3385,22 +2182,21 @@ xfs_free_file_space(
                        break;
                }
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               error = XFS_TRANS_RESERVE_QUOTA(mp, tp,
-                               ip->i_udquot, ip->i_gdquot, resblks, 0,
-                               XFS_QMOPT_RES_REGBLKS);
+               error = xfs_trans_reserve_quota(tp, mp,
+                               ip->i_udquot, ip->i_gdquot,
+                               resblks, 0, XFS_QMOPT_RES_REGBLKS);
                if (error)
                        goto error1;
 
-               xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
 
                /*
                 * issue the bunmapi() call to free the blocks
                 */
-               XFS_BMAP_INIT(&free_list, &firstfsb);
+               xfs_bmap_init(&free_list, &firstfsb);
                error = xfs_bunmapi(tp, ip, startoffset_fsb,
                                  endoffset_fsb - startoffset_fsb,
-                                 0, 2, &firstfsb, &free_list, NULL, &done);
+                                 0, 2, &firstfsb, &free_list, &done);
                if (error) {
                        goto error0;
                }
@@ -3448,7 +2244,6 @@ xfs_change_file_space(
        int             cmd,
        xfs_flock64_t   *bf,
        xfs_off_t       offset,
-       cred_t          *credp,
        int             attr_flags)
 {
        xfs_mount_t     *mp = ip->i_mount;
@@ -3460,8 +2255,7 @@ xfs_change_file_space(
        xfs_off_t       llen;
        xfs_trans_t     *tp;
        struct iattr    iattr;
-
-       xfs_itrace_entry(ip);
+       int             prealloc_type;
 
        if (!S_ISREG(ip->i_d.di_mode))
                return XFS_ERROR(EINVAL);
@@ -3504,12 +2298,17 @@ xfs_change_file_space(
         * size to be changed.
         */
        setprealloc = clrprealloc = 0;
+       prealloc_type = XFS_BMAPI_PREALLOC;
 
        switch (cmd) {
+       case XFS_IOC_ZERO_RANGE:
+               prealloc_type |= XFS_BMAPI_CONVERT;
+               xfs_tosspages(ip, startoffset, startoffset + bf->l_len, 0);
+               /* FALLTHRU */
        case XFS_IOC_RESVSP:
        case XFS_IOC_RESVSP64:
                error = xfs_alloc_file_space(ip, startoffset, bf->l_len,
-                                                               1, attr_flags);
+                                               prealloc_type, attr_flags);
                if (error)
                        return error;
                setprealloc = 1;
@@ -3536,7 +2335,7 @@ xfs_change_file_space(
                iattr.ia_valid = ATTR_SIZE;
                iattr.ia_size = startoffset;
 
-               error = xfs_setattr(ip, &iattr, attr_flags, credp);
+               error = xfs_setattr_size(ip, &iattr, attr_flags);
 
                if (error)
                        return error;
@@ -3563,8 +2362,7 @@ xfs_change_file_space(
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
 
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-       xfs_trans_ihold(tp, ip);
+       xfs_trans_ijoin(tp, ip);
 
        if ((attr_flags & XFS_ATTR_DMI) == 0) {
                ip->i_d.di_mode &= ~S_ISUID;
@@ -3579,7 +2377,7 @@ xfs_change_file_space(
                if (ip->i_d.di_mode & S_IXGRP)
                        ip->i_d.di_mode &= ~S_ISGID;
 
-               xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+               xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
        }
        if (setprealloc)
                ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;
@@ -3587,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);