void xlog_recover_intent_item(struct xlog *log, struct xfs_log_item *lip,
                xfs_lsn_t lsn, unsigned int dfp_type);
+void xlog_recover_transfer_intent(struct xfs_trans *tp,
+               struct xfs_defer_pending *dfp);
 
 #endif /* __XFS_LOG_RECOVER_H__ */
 
 
        args->trans = tp;
        done_item = xfs_trans_get_attrd(tp, attrip);
+       xlog_recover_transfer_intent(tp, dfp);
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, 0);
 
                goto err_rele;
 
        budp = xfs_trans_get_bud(tp, buip);
+       xlog_recover_transfer_intent(tp, dfp);
+
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, 0);
 
 
        error = xfs_trans_alloc(mp, &resv, 0, 0, 0, &tp);
        if (error)
                return error;
+
        efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents);
+       xlog_recover_transfer_intent(tp, dfp);
 
        for (i = 0; i < efip->efi_format.efi_nextents; i++) {
                struct xfs_extent_free_item     fake = {
 
                        break;
                }
 
-               /*
-                * XXX: @lip could have been freed, so detach the log item from
-                * the pending item before freeing the pending item.  This does
-                * not fix the existing UAF bug that occurs if ->iop_recover
-                * fails after creating the intent done item.
-                */
-               dfp->dfp_intent = NULL;
                xfs_defer_cancel_recovery(log->l_mp, dfp);
        }
        if (error)
        }
 }
 
+/*
+ * Transfer ownership of the recovered log intent item to the recovery
+ * transaction.
+ */
+void
+xlog_recover_transfer_intent(
+       struct xfs_trans                *tp,
+       struct xfs_defer_pending        *dfp)
+{
+       dfp->dfp_intent = NULL;
+}
+
 /*
  * This routine performs a transaction to null out a bad inode pointer
  * in an agi unlinked inode hash bucket.
 
                return error;
 
        cudp = xfs_trans_get_cud(tp, cuip);
+       xlog_recover_transfer_intent(tp, dfp);
 
        for (i = 0; i < cuip->cui_format.cui_nextents; i++) {
                struct xfs_refcount_intent      fake = { };
 
                        XFS_TRANS_RESERVE, &tp);
        if (error)
                return error;
+
        rudp = xfs_trans_get_rud(tp, ruip);
+       xlog_recover_transfer_intent(tp, dfp);
 
        for (i = 0; i < ruip->rui_format.rui_nextents; i++) {
                struct xfs_rmap_intent  fake = { };