* Add the extent to the list of extents to be free at transaction end.
  * The list is maintained sorted (by block number).
  */
-int
-xfs_free_extent_later(
+static int
+xfs_defer_extent_free(
        struct xfs_trans                *tp,
        xfs_fsblock_t                   bno,
        xfs_filblks_t                   len,
        const struct xfs_owner_info     *oinfo,
        enum xfs_ag_resv_type           type,
-       bool                            skip_discard)
+       bool                            skip_discard,
+       struct xfs_defer_pending        **dfpp)
 {
        struct xfs_extent_free_item     *xefi;
        struct xfs_mount                *mp = tp->t_mountp;
                        XFS_FSB_TO_AGBNO(tp->t_mountp, bno), len);
 
        xfs_extent_free_get_group(mp, xefi);
-       xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_FREE, &xefi->xefi_list);
+       *dfpp = xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_FREE, &xefi->xefi_list);
+       return 0;
+}
+
+int
+xfs_free_extent_later(
+       struct xfs_trans                *tp,
+       xfs_fsblock_t                   bno,
+       xfs_filblks_t                   len,
+       const struct xfs_owner_info     *oinfo,
+       enum xfs_ag_resv_type           type,
+       bool                            skip_discard)
+{
+       struct xfs_defer_pending        *dontcare = NULL;
+
+       return xfs_defer_extent_free(tp, bno, len, oinfo, type, skip_discard,
+                       &dontcare);
+}
+
+/*
+ * Set up automatic freeing of unwritten space in the filesystem.
+ *
+ * This function attached a paused deferred extent free item to the
+ * transaction.  Pausing means that the EFI will be logged in the next
+ * transaction commit, but the pending EFI will not be finished until the
+ * pending item is unpaused.
+ *
+ * If the system goes down after the EFI has been persisted to the log but
+ * before the pending item is unpaused, log recovery will find the EFI, fail to
+ * find the EFD, and free the space.
+ *
+ * If the pending item is unpaused, the next transaction commit will log an EFD
+ * without freeing the space.
+ *
+ * Caller must ensure that the tp, fsbno, len, oinfo, and resv flags of the
+ * @args structure are set to the relevant values.
+ */
+int
+xfs_alloc_schedule_autoreap(
+       const struct xfs_alloc_arg      *args,
+       bool                            skip_discard,
+       struct xfs_alloc_autoreap       *aarp)
+{
+       int                             error;
+
+       error = xfs_defer_extent_free(args->tp, args->fsbno, args->len,
+                       &args->oinfo, args->resv, skip_discard, &aarp->dfp);
+       if (error)
+               return error;
+
+       xfs_defer_item_pause(args->tp, aarp->dfp);
        return 0;
 }
 
+/*
+ * Cancel automatic freeing of unwritten space in the filesystem.
+ *
+ * Earlier, we created a paused deferred extent free item and attached it to
+ * this transaction so that we could automatically roll back a new space
+ * allocation if the system went down.  Now we want to cancel the paused work
+ * item by marking the EFI stale so we don't actually free the space, unpausing
+ * the pending item and logging an EFD.
+ *
+ * The caller generally should have already mapped the space into the ondisk
+ * filesystem.  If the reserved space was partially used, the caller must call
+ * xfs_free_extent_later to create a new EFI to free the unused space.
+ */
+void
+xfs_alloc_cancel_autoreap(
+       struct xfs_trans                *tp,
+       struct xfs_alloc_autoreap       *aarp)
+{
+       struct xfs_defer_pending        *dfp = aarp->dfp;
+       struct xfs_extent_free_item     *xefi;
+
+       if (!dfp)
+               return;
+
+       list_for_each_entry(xefi, &dfp->dfp_work, xefi_list)
+               xefi->xefi_flags |= XFS_EFI_CANCELLED;
+
+       xfs_defer_item_unpause(tp, dfp);
+}
+
+/*
+ * Commit automatic freeing of unwritten space in the filesystem.
+ *
+ * This unpauses an earlier _schedule_autoreap and commits to freeing the
+ * allocated space.  Call this if none of the reserved space was used.
+ */
+void
+xfs_alloc_commit_autoreap(
+       struct xfs_trans                *tp,
+       struct xfs_alloc_autoreap       *aarp)
+{
+       if (aarp->dfp)
+               xfs_defer_item_unpause(tp, aarp->dfp);
+}
+
 #ifdef DEBUG
 /*
  * Check if an AGF has a free extent record whose length is equal to
 
 #define XFS_EFI_SKIP_DISCARD   (1U << 0) /* don't issue discard */
 #define XFS_EFI_ATTR_FORK      (1U << 1) /* freeing attr fork block */
 #define XFS_EFI_BMBT_BLOCK     (1U << 2) /* freeing bmap btree block */
+#define XFS_EFI_CANCELLED      (1U << 3) /* dont actually free the space */
+
+struct xfs_alloc_autoreap {
+       struct xfs_defer_pending        *dfp;
+};
+
+int xfs_alloc_schedule_autoreap(const struct xfs_alloc_arg *args,
+               bool skip_discard, struct xfs_alloc_autoreap *aarp);
+void xfs_alloc_cancel_autoreap(struct xfs_trans *tp,
+               struct xfs_alloc_autoreap *aarp);
+void xfs_alloc_commit_autoreap(struct xfs_trans *tp,
+               struct xfs_alloc_autoreap *aarp);
 
 extern struct kmem_cache       *xfs_extfree_item_cache;
 
 
        struct xfs_extent               *extp;
        uint                            next_extent;
        xfs_agblock_t                   agbno;
-       int                             error;
+       int                             error = 0;
 
        xefi = container_of(item, struct xfs_extent_free_item, xefi_list);
        agbno = XFS_FSB_TO_AGBNO(mp, xefi->xefi_startblock);
         * the existing EFI, and so we need to copy all the unprocessed extents
         * in this EFI to the EFD so this works correctly.
         */
-       error = __xfs_free_extent(tp, xefi->xefi_pag, agbno,
-                       xefi->xefi_blockcount, &oinfo, xefi->xefi_agresv,
-                       xefi->xefi_flags & XFS_EFI_SKIP_DISCARD);
+       if (!(xefi->xefi_flags & XFS_EFI_CANCELLED))
+               error = __xfs_free_extent(tp, xefi->xefi_pag, agbno,
+                               xefi->xefi_blockcount, &oinfo, xefi->xefi_agresv,
+                               xefi->xefi_flags & XFS_EFI_SKIP_DISCARD);
        if (error == -EAGAIN) {
                xfs_efd_from_efi(efdp);
                return error;