* Check if last_fsb is outside the last extent, and if so grow it to the next
  * stripe unit boundary.
  */
-static xfs_fileoff_t
+xfs_fileoff_t
 xfs_iomap_eof_align_last_fsb(
        struct xfs_inode        *ip,
        xfs_fileoff_t           end_fsb)
 
 int
 xfs_iomap_write_direct(
-       xfs_inode_t     *ip,
-       xfs_off_t       offset,
-       size_t          count,
-       xfs_bmbt_irec_t *imap,
-       int             nmaps)
+       struct xfs_inode        *ip,
+       xfs_fileoff_t           offset_fsb,
+       xfs_fileoff_t           count_fsb,
+       struct xfs_bmbt_irec    *imap)
 {
-       xfs_mount_t     *mp = ip->i_mount;
-       xfs_fileoff_t   offset_fsb = XFS_B_TO_FSBT(mp, offset);
-       xfs_fileoff_t   last_fsb = xfs_iomap_end_fsb(mp, offset, count);
-       xfs_filblks_t   count_fsb, resaligned;
-       xfs_extlen_t    extsz;
-       int             nimaps;
-       int             quota_flag;
-       int             rt;
-       xfs_trans_t     *tp;
-       uint            qblocks, resblks, resrtextents;
-       int             error;
-       int             lockmode;
-       int             bmapi_flags = XFS_BMAPI_PREALLOC;
-       uint            tflags = 0;
-
-       rt = XFS_IS_REALTIME_INODE(ip);
-       extsz = xfs_get_extsz_hint(ip);
-       lockmode = XFS_ILOCK_SHARED;    /* locked by caller */
-
-       ASSERT(xfs_isilocked(ip, lockmode));
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_trans        *tp;
+       xfs_filblks_t           resaligned;
+       int                     nimaps;
+       int                     quota_flag;
+       uint                    qblocks, resblks;
+       unsigned int            resrtextents = 0;
+       int                     error;
+       int                     bmapi_flags = XFS_BMAPI_PREALLOC;
+       uint                    tflags = 0;
 
-       if (offset + count > XFS_ISIZE(ip)) {
-               last_fsb = xfs_iomap_eof_align_last_fsb(ip, last_fsb);
-       } else {
-               if (nmaps && (imap->br_startblock == HOLESTARTBLOCK))
-                       last_fsb = min(last_fsb, (xfs_fileoff_t)
-                                       imap->br_blockcount +
-                                       imap->br_startoff);
-       }
-       count_fsb = last_fsb - offset_fsb;
        ASSERT(count_fsb > 0);
-       resaligned = xfs_aligned_fsb_count(offset_fsb, count_fsb, extsz);
 
-       if (unlikely(rt)) {
+       resaligned = xfs_aligned_fsb_count(offset_fsb, count_fsb,
+                                          xfs_get_extsz_hint(ip));
+       if (unlikely(XFS_IS_REALTIME_INODE(ip))) {
                resrtextents = qblocks = resaligned;
                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, resaligned);
                quota_flag = XFS_QMOPT_RES_REGBLKS;
        }
 
-       /*
-        * Drop the shared lock acquired by the caller, attach the dquot if
-        * necessary and move on to transaction setup.
-        */
-       xfs_iunlock(ip, lockmode);
        error = xfs_qm_dqattach(ip);
        if (error)
                return error;
        if (error)
                return error;
 
-       lockmode = XFS_ILOCK_EXCL;
-       xfs_ilock(ip, lockmode);
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
 
        error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
        if (error)
                error = xfs_alert_fsblock_zero(ip, imap);
 
 out_unlock:
-       xfs_iunlock(ip, lockmode);
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
        return error;
 
 out_res_cancel:
         * lower level functions are updated.
         */
        length = min_t(loff_t, length, 1024 * PAGE_SIZE);
+       end_fsb = xfs_iomap_end_fsb(mp, offset, length);
 
-       /*
-        * xfs_iomap_write_direct() expects the shared lock. It is unlocked on
-        * return.
-        */
-       if (lockmode == XFS_ILOCK_EXCL)
-               xfs_ilock_demote(ip, lockmode);
-       error = xfs_iomap_write_direct(ip, offset, length, &imap, nimaps);
+       if (offset + length > XFS_ISIZE(ip))
+               end_fsb = xfs_iomap_eof_align_last_fsb(ip, end_fsb);
+       else if (nimaps && imap.br_startblock == HOLESTARTBLOCK)
+               end_fsb = min(end_fsb, imap.br_startoff + imap.br_blockcount);
+       xfs_iunlock(ip, lockmode);
+
+       error = xfs_iomap_write_direct(ip, offset_fsb, end_fsb - offset_fsb,
+                       &imap);
        if (error)
                return error;
 
 
 struct xfs_inode;
 struct xfs_bmbt_irec;
 
-int xfs_iomap_write_direct(struct xfs_inode *, xfs_off_t, size_t,
-                       struct xfs_bmbt_irec *, int);
+int xfs_iomap_write_direct(struct xfs_inode *ip, xfs_fileoff_t offset_fsb,
+               xfs_fileoff_t count_fsb, struct xfs_bmbt_irec *imap);
 int xfs_iomap_write_unwritten(struct xfs_inode *, xfs_off_t, xfs_off_t, bool);
+xfs_fileoff_t xfs_iomap_eof_align_last_fsb(struct xfs_inode *ip,
+               xfs_fileoff_t end_fsb);
 
 int xfs_bmbt_to_iomap(struct xfs_inode *, struct iomap *,
                struct xfs_bmbt_irec *, u16);
 
        lock_flags = xfs_ilock_data_map_shared(ip);
        error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
                                &imap, &nimaps, bmapi_flags);
-       xfs_iunlock(ip, lock_flags);
-
-       if (error)
-               goto out_unlock;
 
        ASSERT(!nimaps || imap.br_startblock != DELAYSTARTBLOCK);
 
-       if (write && (!nimaps || imap.br_startblock == HOLESTARTBLOCK)) {
-               /*
-                * xfs_iomap_write_direct() expects to take ownership of the
-                * shared ilock.
-                */
-               xfs_ilock(ip, XFS_ILOCK_SHARED);
-               error = xfs_iomap_write_direct(ip, offset, length, &imap,
-                                              nimaps);
+       if (!error && write &&
+           (!nimaps || imap.br_startblock == HOLESTARTBLOCK)) {
+               if (offset + length > XFS_ISIZE(ip))
+                       end_fsb = xfs_iomap_eof_align_last_fsb(ip, end_fsb);
+               else if (nimaps && imap.br_startblock == HOLESTARTBLOCK)
+                       end_fsb = min(end_fsb, imap.br_startoff +
+                                              imap.br_blockcount);
+               xfs_iunlock(ip, lock_flags);
+
+               error = xfs_iomap_write_direct(ip, offset_fsb,
+                               end_fsb - offset_fsb, &imap);
                if (error)
                        goto out_unlock;
 
                                XFS_PREALLOC_SET | XFS_PREALLOC_SYNC);
                if (error)
                        goto out_unlock;
+       } else {
+               xfs_iunlock(ip, lock_flags);
        }
        xfs_iunlock(ip, XFS_IOLOCK_EXCL);