STATIC int
 xfs_reflink_end_cow_extent(
        struct xfs_inode        *ip,
-       xfs_fileoff_t           offset_fsb,
-       xfs_fileoff_t           *end_fsb)
+       xfs_fileoff_t           *offset_fsb,
+       xfs_fileoff_t           end_fsb)
 {
-       struct xfs_bmbt_irec    got, del;
        struct xfs_iext_cursor  icur;
+       struct xfs_bmbt_irec    got, del, data;
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
        struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
-       xfs_filblks_t           rlen;
        unsigned int            resblks;
+       int                     nmaps;
        int                     error;
 
        /* No COW extents?  That's easy! */
        if (ifp->if_bytes == 0) {
-               *end_fsb = offset_fsb;
+               *offset_fsb = end_fsb;
                return 0;
        }
 
         * left by the time I/O completes for the loser of the race.  In that
         * case we are done.
         */
-       if (!xfs_iext_lookup_extent_before(ip, ifp, end_fsb, &icur, &got) ||
-           got.br_startoff + got.br_blockcount <= offset_fsb) {
-               *end_fsb = offset_fsb;
+       if (!xfs_iext_lookup_extent(ip, ifp, *offset_fsb, &icur, &got) ||
+           got.br_startoff >= end_fsb) {
+               *offset_fsb = end_fsb;
                goto out_cancel;
        }
 
-       /*
-        * Structure copy @got into @del, then trim @del to the range that we
-        * were asked to remap.  We preserve @got for the eventual CoW fork
-        * deletion; from now on @del represents the mapping that we're
-        * actually remapping.
-        */
-       del = got;
-       xfs_trim_extent(&del, offset_fsb, *end_fsb - offset_fsb);
-
-       ASSERT(del.br_blockcount > 0);
-
        /*
         * Only remap real extents that contain data.  With AIO, speculative
         * preallocations can leak into the range we are called upon, and we
-        * need to skip them.
+        * need to skip them.  Preserve @got for the eventual CoW fork
+        * deletion; from now on @del represents the mapping that we're
+        * actually remapping.
         */
-       if (!xfs_bmap_is_written_extent(&got)) {
-               *end_fsb = del.br_startoff;
-               goto out_cancel;
+       while (!xfs_bmap_is_written_extent(&got)) {
+               if (!xfs_iext_next_extent(ifp, &icur, &got) ||
+                   got.br_startoff >= end_fsb) {
+                       *offset_fsb = end_fsb;
+                       goto out_cancel;
+               }
        }
+       del = got;
 
-       /* Unmap the old blocks in the data fork. */
-       rlen = del.br_blockcount;
-       error = __xfs_bunmapi(tp, ip, del.br_startoff, &rlen, 0, 1);
+       /* Grab the corresponding mapping in the data fork. */
+       nmaps = 1;
+       error = xfs_bmapi_read(ip, del.br_startoff, del.br_blockcount, &data,
+                       &nmaps, 0);
        if (error)
                goto out_cancel;
 
-       /* Trim the extent to whatever got unmapped. */
-       xfs_trim_extent(&del, del.br_startoff + rlen, del.br_blockcount - rlen);
-       trace_xfs_reflink_cow_remap(ip, &del);
+       /* We can only remap the smaller of the two extent sizes. */
+       data.br_blockcount = min(data.br_blockcount, del.br_blockcount);
+       del.br_blockcount = data.br_blockcount;
+
+       trace_xfs_reflink_cow_remap_from(ip, &del);
+       trace_xfs_reflink_cow_remap_to(ip, &data);
+
+       if (xfs_bmap_is_real_extent(&data)) {
+               /*
+                * If the extent we're remapping is backed by storage (written
+                * or not), unmap the extent and drop its refcount.
+                */
+               xfs_bmap_unmap_extent(tp, ip, &data);
+               xfs_refcount_decrease_extent(tp, &data);
+               xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT,
+                               -data.br_blockcount);
+       } else if (data.br_startblock == DELAYSTARTBLOCK) {
+               int             done;
+
+               /*
+                * If the extent we're remapping is a delalloc reservation,
+                * we can use the regular bunmapi function to release the
+                * incore state.  Dropping the delalloc reservation takes care
+                * of the quota reservation for us.
+                */
+               error = xfs_bunmapi(NULL, ip, data.br_startoff,
+                               data.br_blockcount, 0, 1, &done);
+               if (error)
+                       goto out_cancel;
+               ASSERT(done);
+       }
 
        /* Free the CoW orphan record. */
        xfs_refcount_free_cow_extent(tp, del.br_startblock, del.br_blockcount);
                return error;
 
        /* Update the caller about how much progress we made. */
-       *end_fsb = del.br_startoff;
+       *offset_fsb = del.br_startoff + del.br_blockcount;
        return 0;
 
 out_cancel:
        end_fsb = XFS_B_TO_FSB(ip->i_mount, offset + count);
 
        /*
-        * Walk backwards until we're out of the I/O range.  The loop function
+        * Walk forwards until we've remapped the I/O range.  The loop function
         * repeatedly cycles the ILOCK to allocate one transaction per remapped
         * extent.
         *
         * blocks will be remapped.
         */
        while (end_fsb > offset_fsb && !error)
-               error = xfs_reflink_end_cow_extent(ip, offset_fsb, &end_fsb);
+               error = xfs_reflink_end_cow_extent(ip, &offset_fsb, end_fsb);
 
        if (error)
                trace_xfs_reflink_end_cow_error(ip, error, _RET_IP_);