int                     whichfork;      /* data or attribute fork */
        xfs_fsblock_t           sum;
        xfs_filblks_t           len = *rlen;    /* length to unmap in file */
+       xfs_fileoff_t           max_len;
 
        trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_);
 
        ASSERT(len > 0);
        ASSERT(nexts >= 0);
 
+       /*
+        * Guesstimate how many blocks we can unmap without running the risk of
+        * blowing out the transaction with a mix of EFIs and reflink
+        * adjustments.
+        */
+       if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK)
+               max_len = min(len, xfs_refcount_max_unmap(tp->t_log_res));
+       else
+               max_len = len;
+
        if (!(ifp->if_flags & XFS_IFEXTENTS) &&
            (error = xfs_iread_extents(tp, ip, whichfork)))
                return error;
 
        extno = 0;
        while (bno != (xfs_fileoff_t)-1 && bno >= start && lastx >= 0 &&
-              (nexts == 0 || extno < nexts)) {
+              (nexts == 0 || extno < nexts) && max_len > 0) {
                /*
                 * Is the found extent after a hole in which bno lives?
                 * Just back up to the previous extent, if so.
                }
                if (del.br_startoff + del.br_blockcount > bno + 1)
                        del.br_blockcount = bno + 1 - del.br_startoff;
+
+               /* How much can we safely unmap? */
+               if (max_len < del.br_blockcount) {
+                       del.br_startoff += del.br_blockcount - max_len;
+                       if (!wasdel)
+                               del.br_startblock += del.br_blockcount - max_len;
+                       del.br_blockcount = max_len;
+               }
+
                sum = del.br_startblock + del.br_blockcount;
                if (isrt &&
                    (mod = do_mod(sum, mp->m_sb.sb_rextsize))) {
                if (!isrt && wasdel)
                        xfs_mod_fdblocks(mp, (int64_t)del.br_blockcount, false);
 
+               max_len -= del.br_blockcount;
                bno = del.br_startoff - 1;
 nodelete:
                /*
        int                             whichfork,
        xfs_fileoff_t                   startoff,
        xfs_fsblock_t                   startblock,
-       xfs_filblks_t                   blockcount,
+       xfs_filblks_t                   *blockcount,
        xfs_exntst_t                    state)
 {
-       int                             error = 0, done;
+       xfs_fsblock_t                   firstfsb;
+       int                             error = 0;
 
        trace_xfs_bmap_deferred(tp->t_mountp,
                        XFS_FSB_TO_AGNO(tp->t_mountp, startblock), type,
                        XFS_FSB_TO_AGBNO(tp->t_mountp, startblock),
-                       ip->i_ino, whichfork, startoff, blockcount, state);
+                       ip->i_ino, whichfork, startoff, *blockcount, state);
 
        if (WARN_ON_ONCE(whichfork != XFS_DATA_FORK))
                return -EFSCORRUPTED;
 
        switch (type) {
        case XFS_BMAP_MAP:
-               error = xfs_bmapi_remap(tp, ip, startoff, blockcount,
+               error = xfs_bmapi_remap(tp, ip, startoff, *blockcount,
                                startblock, dfops);
+               *blockcount = 0;
                break;
        case XFS_BMAP_UNMAP:
-               error = xfs_bunmapi(tp, ip, startoff, blockcount,
-                               XFS_BMAPI_REMAP, 1, &startblock, dfops, &done);
-               ASSERT(done);
+               error = __xfs_bunmapi(tp, ip, startoff, blockcount,
+                               XFS_BMAPI_REMAP, 1, &firstfsb, dfops);
                break;
        default:
                ASSERT(0);
 
 int    xfs_bmap_finish_one(struct xfs_trans *tp, struct xfs_defer_ops *dfops,
                struct xfs_inode *ip, enum xfs_bmap_intent_type type,
                int whichfork, xfs_fileoff_t startoff, xfs_fsblock_t startblock,
-               xfs_filblks_t blockcount, xfs_exntst_t state);
+               xfs_filblks_t *blockcount, xfs_exntst_t state);
 int    xfs_bmap_map_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
                struct xfs_inode *ip, struct xfs_bmbt_irec *imap);
 int    xfs_bmap_unmap_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
 
 }
 
 /*
- * While we're adjusting the refcounts records of an extent, we have
- * to keep an eye on the number of extents we're dirtying -- run too
- * many in a single transaction and we'll exceed the transaction's
- * reservation and crash the fs.  Each record adds 12 bytes to the
- * log (plus any key updates) so we'll conservatively assume 24 bytes
- * per record.  We must also leave space for btree splits on both ends
- * of the range and space for the CUD and a new CUI.
- *
  * XXX: This is a pretty hand-wavy estimate.  The penalty for guessing
  * true incorrectly is a shutdown FS; the penalty for guessing false
  * incorrectly is more transaction rolls than might be necessary.
        else if (overhead > cur->bc_tp->t_log_res)
                return false;
        return  cur->bc_tp->t_log_res - overhead >
-               cur->bc_private.a.priv.refc.nr_ops * 32;
+               cur->bc_private.a.priv.refc.nr_ops * XFS_REFCOUNT_ITEM_OVERHEAD;
 }
 
 /*
 
 extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp,
                xfs_agnumber_t agno);
 
+/*
+ * While we're adjusting the refcounts records of an extent, we have
+ * to keep an eye on the number of extents we're dirtying -- run too
+ * many in a single transaction and we'll exceed the transaction's
+ * reservation and crash the fs.  Each record adds 12 bytes to the
+ * log (plus any key updates) so we'll conservatively assume 32 bytes
+ * per record.  We must also leave space for btree splits on both ends
+ * of the range and space for the CUD and a new CUI.
+ */
+#define XFS_REFCOUNT_ITEM_OVERHEAD     32
+
+static inline xfs_fileoff_t xfs_refcount_max_unmap(int log_res)
+{
+       return (log_res * 3 / 4) / XFS_REFCOUNT_ITEM_OVERHEAD;
+}
+
 #endif /* __XFS_REFCOUNT_H__ */
 
        struct xfs_map_extent           *bmap;
        xfs_fsblock_t                   startblock_fsb;
        xfs_fsblock_t                   inode_fsb;
+       xfs_filblks_t                   count;
        bool                            op_ok;
        struct xfs_bud_log_item         *budp;
        enum xfs_bmap_intent_type       type;
        struct xfs_trans                *tp;
        struct xfs_inode                *ip = NULL;
        struct xfs_defer_ops            dfops;
+       struct xfs_bmbt_irec            irec;
        xfs_fsblock_t                   firstfsb;
 
        ASSERT(!test_bit(XFS_BUI_RECOVERED, &buip->bui_flags));
        }
        xfs_trans_ijoin(tp, ip, 0);
 
+       count = bmap->me_len;
        error = xfs_trans_log_finish_bmap_update(tp, budp, &dfops, type,
                        ip, whichfork, bmap->me_startoff,
-                       bmap->me_startblock, bmap->me_len,
-                       state);
+                       bmap->me_startblock, &count, state);
        if (error)
                goto err_dfops;
 
+       if (count > 0) {
+               ASSERT(type == XFS_BMAP_UNMAP);
+               irec.br_startblock = bmap->me_startblock;
+               irec.br_blockcount = count;
+               irec.br_startoff = bmap->me_startoff;
+               irec.br_state = state;
+               error = xfs_bmap_unmap_extent(tp->t_mountp, &dfops, ip, &irec);
+               if (error)
+                       goto err_dfops;
+       }
+
        /* Finish transaction, free inodes. */
        error = xfs_defer_finish(&tp, &dfops, NULL);
        if (error)
 
                struct xfs_bud_log_item *rudp, struct xfs_defer_ops *dfops,
                enum xfs_bmap_intent_type type, struct xfs_inode *ip,
                int whichfork, xfs_fileoff_t startoff, xfs_fsblock_t startblock,
-               xfs_filblks_t blockcount, xfs_exntst_t state);
+               xfs_filblks_t *blockcount, xfs_exntst_t state);
 
 #endif /* __XFS_TRANS_H__ */
 
        int                             whichfork,
        xfs_fileoff_t                   startoff,
        xfs_fsblock_t                   startblock,
-       xfs_filblks_t                   blockcount,
+       xfs_filblks_t                   *blockcount,
        xfs_exntst_t                    state)
 {
        int                             error;
        void                            **state)
 {
        struct xfs_bmap_intent          *bmap;
+       xfs_filblks_t                   count;
        int                             error;
 
        bmap = container_of(item, struct xfs_bmap_intent, bi_list);
+       count = bmap->bi_bmap.br_blockcount;
        error = xfs_trans_log_finish_bmap_update(tp, done_item, dop,
                        bmap->bi_type,
                        bmap->bi_owner, bmap->bi_whichfork,
                        bmap->bi_bmap.br_startoff,
                        bmap->bi_bmap.br_startblock,
-                       bmap->bi_bmap.br_blockcount,
+                       &count,
                        bmap->bi_bmap.br_state);
+       if (!error && count > 0) {
+               ASSERT(bmap->bi_type == XFS_BMAP_UNMAP);
+               bmap->bi_bmap.br_blockcount = count;
+               return -EAGAIN;
+       }
        kmem_free(bmap);
        return error;
 }