*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
***************
*** 4617,4639 **** xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn,
  	}
  
  	/* Make sure files supposed to be dropped are dropped */
! 	for (i = 0; i < nrels; i++)
  	{
! 		SMgrRelation srel = smgropen(xnodes[i], InvalidBackendId);
! 		ForkNumber	fork;
  
! 		for (fork = 0; fork <= MAX_FORKNUM; fork++)
! 			XLogDropRelation(xnodes[i], fork);
! 		smgrdounlink(srel, true);
! 		smgrclose(srel);
  	}
  
  	/*
  	 * We issue an XLogFlush() for the same reason we emit ForceSyncCommit()
! 	 * in normal operation. For example, in DROP DATABASE, we delete all the
! 	 * files belonging to the database, and then commit the transaction. If we
! 	 * crash after all the files have been deleted but before the commit, you
! 	 * have an entry in pg_database without any files. To minimize the window
  	 * for that, we use ForceSyncCommit() to rush the commit record to disk as
  	 * quick as possible. We have the same window during recovery, and forcing
  	 * an XLogFlush() (which updates minRecoveryPoint during recovery) helps
--- 4617,4660 ----
  	}
  
  	/* Make sure files supposed to be dropped are dropped */
! 	if (nrels > 0)
  	{
! 		/*
! 		 * First update minimum recovery point to cover this WAL record. Once
! 		 * a relation is deleted, there's no going back. The buffer manager
! 		 * enforces the WAL-first rule for normal updates to relation files,
! 		 * so that the minimum recovery point is always updated before the
! 		 * corresponding change in the data file is flushed to disk, but we
! 		 * have to do the same here since we're bypassing the buffer manager.
! 		 *
! 		 * Doing this before the deleting the files means that if a deletion
! 		 * fails for some reason, you cannot start up the system even after
! 		 * restart, until you fix the underlying situation so that the
! 		 * deletion will succeed. Alternatively, we could update the minimum
! 		 * recovery point after deletion, but that would leave a small window
! 		 * where the WAL-first rule would be violated.
! 		 */
! 		XLogFlush(lsn);
  
! 		for (i = 0; i < nrels; i++)
! 		{
! 			SMgrRelation srel = smgropen(xnodes[i], InvalidBackendId);
! 			ForkNumber	fork;
! 
! 			for (fork = 0; fork <= MAX_FORKNUM; fork++)
! 				XLogDropRelation(xnodes[i], fork);
! 			smgrdounlink(srel, true);
! 			smgrclose(srel);
! 		}
  	}
  
  	/*
  	 * We issue an XLogFlush() for the same reason we emit ForceSyncCommit()
! 	 * in normal operation. For example, in CREATE DATABASE, we copy all the
! 	 * files from the template database, and then commit the transaction. If we
! 	 * crash after all the files have been copied but before the commit, you
! 	 * have files in the data directory without an entry in pg_database.
! 	 * To minimize the window
  	 * for that, we use ForceSyncCommit() to rush the commit record to disk as
  	 * quick as possible. We have the same window during recovery, and forcing
  	 * an XLogFlush() (which updates minRecoveryPoint during recovery) helps
*** a/src/backend/catalog/storage.c
--- b/src/backend/catalog/storage.c
***************
*** 482,487 **** smgr_redo(XLogRecPtr lsn, XLogRecord *record)
--- 482,504 ----
  		 */
  		smgrcreate(reln, MAIN_FORKNUM, true);
  
+ 		/*
+ 		 * Before we perform the truncation, update minimum recovery point
+ 		 * to cover this WAL record. Once the relation is truncated, there's
+ 		 * no going back. The buffer manager enforces the WAL-first rule
+ 		 * for normal updates to relation files, so that the minimum recovery
+ 		 * point is always updated before the corresponding change in the
+ 		 * data file is flushed to disk.
+ 		 *
+ 		 * Doing this before the truncation means that if the truncation fails
+ 		 * for some reason, you cannot start up the system even after restart,
+ 		 * until you fix the underlying situation so that the truncation will
+ 		 * succeed. Alternatively, we could update the minimum recovery point
+ 		 * after truncation, but that would leave a small window where the
+ 		 * WAL-first rule could be violated.
+ 		 */
+ 		XLogFlush(lsn);
+ 
  		smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
  
  		/* Also tell xlogutils.c about it */
