diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index 5c2b0c7635..a26e00c988 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -1152,7 +1152,8 @@ terminate_brin_buildstate(BrinBuildState *state)
 		freespace = PageGetFreeSpace(page);
 		blk = BufferGetBlockNumber(state->bs_currentInsertBuf);
 		ReleaseBuffer(state->bs_currentInsertBuf);
-		RecordPageWithFreeSpace(state->bs_irel, blk, freespace, InvalidBlockNumber);
+		RecordPageWithFreeSpace(state->bs_irel, blk, freespace, InvalidBlockNumber,
+								BRIN_FSM_CREATION_THRESHOLD);
 		FreeSpaceMapVacuumRange(state->bs_irel, blk, blk + 1);
 	}
 
diff --git a/src/backend/access/brin/brin_pageops.c b/src/backend/access/brin/brin_pageops.c
index 2e83aa42f7..56f6b0a6ba 100644
--- a/src/backend/access/brin/brin_pageops.c
+++ b/src/backend/access/brin/brin_pageops.c
@@ -310,7 +310,8 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
 
 		if (extended)
 		{
-			RecordPageWithFreeSpace(idxrel, newblk, freespace, InvalidBlockNumber);
+			RecordPageWithFreeSpace(idxrel, newblk, freespace, InvalidBlockNumber,
+									BRIN_FSM_CREATION_THRESHOLD);
 			FreeSpaceMapVacuumRange(idxrel, newblk, newblk + 1);
 		}
 
@@ -461,7 +462,8 @@ brin_doinsert(Relation idxrel, BlockNumber pagesPerRange,
 
 	if (extended)
 	{
-		RecordPageWithFreeSpace(idxrel, blk, freespace, InvalidBlockNumber);
+		RecordPageWithFreeSpace(idxrel, blk, freespace, InvalidBlockNumber,
+								BRIN_FSM_CREATION_THRESHOLD);
 		FreeSpaceMapVacuumRange(idxrel, blk, blk + 1);
 	}
 
@@ -654,7 +656,8 @@ brin_page_cleanup(Relation idxrel, Buffer buf)
 
 	/* Measure free space and record it */
 	RecordPageWithFreeSpace(idxrel, BufferGetBlockNumber(buf),
-							br_page_get_freespace(page), InvalidBlockNumber);
+							br_page_get_freespace(page), InvalidBlockNumber,
+							BRIN_FSM_CREATION_THRESHOLD);
 }
 
 /*
@@ -703,7 +706,7 @@ brin_getinsertbuffer(Relation irel, Buffer oldbuf, Size itemsz,
 	/* Choose initial target page, re-using existing target if known */
 	newblk = RelationGetTargetBlock(irel);
 	if (newblk == InvalidBlockNumber)
-		newblk = GetPageWithFreeSpace(irel, itemsz, true);
+		newblk = GetPageWithFreeSpace(irel, itemsz);
 
 	/*
 	 * Loop until we find a page with sufficient free space.  By the time we
@@ -855,7 +858,8 @@ brin_getinsertbuffer(Relation irel, Buffer oldbuf, Size itemsz,
 		 * Update the FSM with the new, presumably smaller, freespace value
 		 * for this page, then search for a new target page.
 		 */
-		newblk = RecordAndGetPageWithFreeSpace(irel, newblk, freespace, itemsz);
+		newblk = RecordAndGetPageWithFreeSpace(irel, newblk, freespace, itemsz,
+											   BRIN_FSM_CREATION_THRESHOLD);
 	}
 }
 
@@ -895,7 +899,8 @@ brin_initialize_empty_new_buffer(Relation idxrel, Buffer buffer)
 	 * pages whose FSM records were forgotten in a crash.
 	 */
 	RecordPageWithFreeSpace(idxrel, BufferGetBlockNumber(buffer),
-							br_page_get_freespace(page), InvalidBlockNumber);
+							br_page_get_freespace(page), InvalidBlockNumber,
+							BRIN_FSM_CREATION_THRESHOLD);
 }
 
 
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index a05b6a07ad..24f33b2b0c 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -7747,7 +7747,8 @@ heap_xlog_clean(XLogReaderState *record)
 		 * Do this regardless of a full-page image being applied, since the
 		 * FSM data is not in the page anyway.
 		 */
-		XLogRecordPageWithFreeSpace(rnode, blkno, freespace);
+		XLogRecordPageWithFreeSpace(rnode, blkno, freespace,
+									HEAP_FSM_CREATION_THRESHOLD);
 	}
 }
 
@@ -7846,7 +7847,8 @@ heap_xlog_visible(XLogReaderState *record)
 		 * FSM data is not in the page anyway.
 		 */
 		if (xlrec->flags & VISIBILITYMAP_VALID_BITS)
-			XLogRecordPageWithFreeSpace(rnode, blkno, space);
+			XLogRecordPageWithFreeSpace(rnode, blkno, space,
+										HEAP_FSM_CREATION_THRESHOLD);
 	}
 
 	/*
@@ -8161,7 +8163,8 @@ heap_xlog_insert(XLogReaderState *record)
 	 * totally accurate anyway.
 	 */
 	if (action == BLK_NEEDS_REDO && freespace < BLCKSZ / 5)
-		XLogRecordPageWithFreeSpace(target_node, blkno, freespace);
+		XLogRecordPageWithFreeSpace(target_node, blkno, freespace,
+									HEAP_FSM_CREATION_THRESHOLD);
 }
 
 /*
@@ -8300,7 +8303,8 @@ heap_xlog_multi_insert(XLogReaderState *record)
 	 * totally accurate anyway.
 	 */
 	if (action == BLK_NEEDS_REDO && freespace < BLCKSZ / 5)
-		XLogRecordPageWithFreeSpace(rnode, blkno, freespace);
+		XLogRecordPageWithFreeSpace(rnode, blkno, freespace,
+									HEAP_FSM_CREATION_THRESHOLD);
 }
 
 /*
@@ -8575,7 +8579,8 @@ heap_xlog_update(XLogReaderState *record, bool hot_update)
 	 * totally accurate anyway.
 	 */
 	if (newaction == BLK_NEEDS_REDO && !hot_update && freespace < BLCKSZ / 5)
-		XLogRecordPageWithFreeSpace(rnode, newblk, freespace);
+		XLogRecordPageWithFreeSpace(rnode, newblk, freespace,
+									HEAP_FSM_CREATION_THRESHOLD);
 }
 
 static void
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c
index 69a7a23874..863a3ce27f 100644
--- a/src/backend/access/heap/hio.c
+++ b/src/backend/access/heap/hio.c
@@ -253,7 +253,8 @@ RelationAddExtraBlocks(Relation relation, BulkInsertState bistate)
 		 * first new page.
 		 */
 		RecordPageWithFreeSpace(relation, blockNum, freespace,
-								firstBlock + extraBlocks);
+								firstBlock + extraBlocks,
+								HEAP_FSM_CREATION_THRESHOLD);
 	}
 	while (--extraBlocks > 0);
 
@@ -390,9 +391,11 @@ RelationGetBufferForTuple(Relation relation, Size len,
 		 * We have no cached target page, so ask the FSM for an initial
 		 * target.
 		 */
-		targetBlock = GetPageWithFreeSpace(relation,
-										   len + saveFreeSpace,
-										   false);
+		targetBlock = GetPageWithFreeSpace(relation, len + saveFreeSpace);
+
+		if (targetBlock == InvalidBlockNumber)
+			targetBlock = GetAlternatePage(relation,
+										   HEAP_FSM_CREATION_THRESHOLD);
 	}
 
 loop:
@@ -535,7 +538,8 @@ loop:
 		targetBlock = RecordAndGetPageWithFreeSpace(relation,
 													targetBlock,
 													pageFreeSpace,
-													len + saveFreeSpace);
+													len + saveFreeSpace,
+													HEAP_FSM_CREATION_THRESHOLD);
 	}
 
 	/*
@@ -565,12 +569,9 @@ loop:
 
 			/*
 			 * Check if some other backend has extended a block for us while
-			 * we were waiting on the lock.  We only check the FSM -- if there
-			 * isn't one we don't recheck the number of blocks.
+			 * we were waiting on the lock.
 			 */
-			targetBlock = GetPageWithFreeSpace(relation,
-											   len + saveFreeSpace,
-											   true);
+			targetBlock = GetPageWithFreeSpace(relation, len + saveFreeSpace);
 
 			/*
 			 * If some other waiter has already extended the relation, we
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 8dc76fa858..f064b1502a 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -927,7 +927,8 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
 					Size		freespace;
 
 					freespace = BufferGetPageSize(buf) - SizeOfPageHeaderData;
-					RecordPageWithFreeSpace(onerel, blkno, freespace, nblocks);
+					RecordPageWithFreeSpace(onerel, blkno, freespace, nblocks,
+											HEAP_FSM_CREATION_THRESHOLD);
 				}
 			}
 			continue;
@@ -971,7 +972,8 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
 			}
 
 			UnlockReleaseBuffer(buf);
-			RecordPageWithFreeSpace(onerel, blkno, freespace, nblocks);
+			RecordPageWithFreeSpace(onerel, blkno, freespace, nblocks,
+									HEAP_FSM_CREATION_THRESHOLD);
 			continue;
 		}
 
@@ -1395,7 +1397,8 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
 		 * taken if there are no indexes.)
 		 */
 		if (vacrelstats->num_dead_tuples == prev_dead_count)
-			RecordPageWithFreeSpace(onerel, blkno, freespace, nblocks);
+			RecordPageWithFreeSpace(onerel, blkno, freespace, nblocks,
+									HEAP_FSM_CREATION_THRESHOLD);
 	}
 
 	/* No dead tuples should be left if index cleanup is enabled */
@@ -1580,7 +1583,8 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats, BlockNumber nblocks)
 		freespace = PageGetHeapFreeSpace(page);
 
 		UnlockReleaseBuffer(buf);
-		RecordPageWithFreeSpace(onerel, tblk, freespace, nblocks);
+		RecordPageWithFreeSpace(onerel, tblk, freespace, nblocks,
+								HEAP_FSM_CREATION_THRESHOLD);
 		npages++;
 	}
 
diff --git a/src/backend/storage/freespace/README b/src/backend/storage/freespace/README
index 0d3cd29772..64b1a34a5c 100644
--- a/src/backend/storage/freespace/README
+++ b/src/backend/storage/freespace/README
@@ -13,7 +13,7 @@ fixed-size FSM.  There are two exceptions:
 1. Hash indexes never have a FSM.
 2. For very small tables, a 3-page relation fork would be relatively large
 and wasteful, so to save space we refrain from creating the FSM if the
-heap has HEAP_FSM_CREATION_THRESHOLD pages or fewer.
+heap has less than or equal to some threshold number of pages.
 
 To locate free space in the latter case, we simply try pages directly without
 knowing ahead of time how much free space they have.  To maintain good
diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c
index c3ed4242e2..164e70791f 100644
--- a/src/backend/storage/freespace/freespace.c
+++ b/src/backend/storage/freespace/freespace.c
@@ -76,14 +76,6 @@
 #define FSM_ROOT_LEVEL	(FSM_TREE_DEPTH - 1)
 #define FSM_BOTTOM_LEVEL 0
 
-/* Status codes for the local map. */
-
-/* Either already tried, or beyond the end of the relation */
-#define FSM_LOCAL_NOT_AVAIL 0x00
-
-/* Available to try */
-#define FSM_LOCAL_AVAIL		0x01
-
 /*
  * The internal FSM routines work on a logical addressing scheme. Each
  * level of the tree can be thought of as a separately addressable file.
@@ -110,18 +102,15 @@ static const FSMAddress FSM_ROOT_ADDRESS = {FSM_ROOT_LEVEL, 0};
 typedef struct
 {
 	BlockNumber nblocks;
-	uint8		map[HEAP_FSM_CREATION_THRESHOLD];
+	uint32		map;
 }			FSMLocalMap;
 
-static FSMLocalMap fsm_local_map =
-{
-	0,
-	{
-		FSM_LOCAL_NOT_AVAIL
-	}
-};
+static FSMLocalMap fsm_local_map = { 0, 0 };
 
 #define FSM_LOCAL_MAP_EXISTS (fsm_local_map.nblocks > 0)
+#define FSM_LOCAL_MAP_IS_AVAIL(page) (fsm_local_map.map & (1 << page))
+#define FSM_LOCAL_MAP_SET_AVAIL(page) (fsm_local_map.map |= (1 << page))
+#define FSM_LOCAL_MAP_SET_UNAVAIL(page) (fsm_local_map.map &= ~(1 << page))
 
 /* functions to navigate the tree */
 static FSMAddress fsm_get_child(FSMAddress parent, uint16 slot);
@@ -148,7 +137,8 @@ static uint8 fsm_vacuum_page(Relation rel, FSMAddress addr,
 				BlockNumber start, BlockNumber end,
 				bool *eof);
 static bool fsm_allow_writes(Relation rel, BlockNumber heapblk,
-				 BlockNumber nblocks, BlockNumber *get_nblocks);
+				 BlockNumber nblocks, BlockNumber *get_nblocks,
+				 BlockNumber FSMCreationThreshold);
 
 
 /******** Public API ********/
@@ -164,44 +154,46 @@ static bool fsm_allow_writes(Relation rel, BlockNumber heapblk,
  * gets a lock on it.  In that case, the caller should report the actual
  * amount of free space available on that page and then try again (see
  * RecordAndGetPageWithFreeSpace).  If InvalidBlockNumber is returned,
- * extend the relation.
+ * either find a block some other way or extend the relation.
+ */
+BlockNumber
+GetPageWithFreeSpace(Relation rel, Size spaceNeeded)
+{
+	uint8		min_cat = fsm_space_needed_to_cat(spaceNeeded);
+
+	return fsm_search(rel, min_cat);
+}
+
+/*
+ * If the FSM knows nothing of the rel, try some other page before
+ * we give up and extend.
  *
  * For very small heap relations that don't have a FSM, we try every other
  * page before extending the relation.  To keep track of which pages have
  * been tried, initialize a local in-memory map of pages.
  */
 BlockNumber
-GetPageWithFreeSpace(Relation rel, Size spaceNeeded, bool check_fsm_only)
+GetAlternatePage(Relation rel, BlockNumber FSMCreationThreshold)
 {
-	uint8		min_cat = fsm_space_needed_to_cat(spaceNeeded);
-	BlockNumber target_block,
+	BlockNumber target_block = InvalidBlockNumber,
 				nblocks;
 
-	/* First try the FSM, if it exists. */
-	target_block = fsm_search(rel, min_cat);
+	nblocks = RelationGetNumberOfBlocks(rel);
 
-	if (target_block == InvalidBlockNumber &&
-		(rel->rd_rel->relkind == RELKIND_RELATION ||
-		 rel->rd_rel->relkind == RELKIND_TOASTVALUE) &&
-		!check_fsm_only)
+	if (nblocks > FSMCreationThreshold)
 	{
-		nblocks = RelationGetNumberOfBlocks(rel);
-
-		if (nblocks > HEAP_FSM_CREATION_THRESHOLD)
-		{
-			/*
-			 * If the FSM knows nothing of the rel, try the last page before
-			 * we give up and extend.  This avoids one-tuple-per-page syndrome
-			 * during bootstrapping or in a recently-started system.
-			 */
-			target_block = nblocks - 1;
-		}
-		else if (nblocks > 0)
-		{
-			/* Initialize local map and get first candidate block. */
-			fsm_local_set(rel, nblocks);
-			target_block = fsm_local_search();
-		}
+		/*
+		 * If the FSM knows nothing of the rel, try the last page before
+		 * we give up and extend.  This avoids one-tuple-per-page syndrome
+		 * during bootstrapping or in a recently-started system.
+		 */
+		target_block = nblocks - 1;
+	}
+	else if (nblocks > 0)
+	{
+		/* Initialize local map and get first candidate block. */
+		fsm_local_set(rel, nblocks);
+		target_block = fsm_local_search();
 	}
 
 	return target_block;
@@ -221,7 +213,8 @@ GetPageWithFreeSpace(Relation rel, Size spaceNeeded, bool check_fsm_only)
  */
 BlockNumber
 RecordAndGetPageWithFreeSpace(Relation rel, BlockNumber oldPage,
-							  Size oldSpaceAvail, Size spaceNeeded)
+							  Size oldSpaceAvail, Size spaceNeeded,
+							  BlockNumber FSMCreationThreshold)
 {
 	int			old_cat;
 	int			search_cat;
@@ -233,15 +226,14 @@ RecordAndGetPageWithFreeSpace(Relation rel, BlockNumber oldPage,
 	/* First try the local map, if it exists. */
 	if (FSM_LOCAL_MAP_EXISTS)
 	{
-		Assert((rel->rd_rel->relkind == RELKIND_RELATION ||
-				rel->rd_rel->relkind == RELKIND_TOASTVALUE) &&
-			   fsm_local_map.map[oldPage] == FSM_LOCAL_AVAIL);
+		Assert(FSM_LOCAL_MAP_IS_AVAIL(oldPage));
 
-		fsm_local_map.map[oldPage] = FSM_LOCAL_NOT_AVAIL;
+		FSM_LOCAL_MAP_SET_UNAVAIL(oldPage);
 		return fsm_local_search();
 	}
 
-	if (!fsm_allow_writes(rel, oldPage, InvalidBlockNumber, &nblocks))
+	if (!fsm_allow_writes(rel, oldPage, InvalidBlockNumber,
+						  &nblocks, FSMCreationThreshold))
 	{
 		/*
 		 * If we have neither a local map nor a FSM, we probably just tried
@@ -278,19 +270,18 @@ RecordAndGetPageWithFreeSpace(Relation rel, BlockNumber oldPage,
  * Note that if the new spaceAvail value is higher than the old value stored
  * in the FSM, the space might not become visible to searchers until the next
  * FreeSpaceMapVacuum call, which updates the upper level pages.
- *
- * Callers have no need for a local map.
  */
 void
 RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk,
-						Size spaceAvail, BlockNumber nblocks)
+						Size spaceAvail, BlockNumber nblocks,
+						BlockNumber FSMCreationThreshold)
 {
 	int			new_cat;
 	FSMAddress	addr;
 	uint16		slot;
 	BlockNumber dummy;
 
-	if (!fsm_allow_writes(rel, heapBlk, nblocks, &dummy))
+	if (!fsm_allow_writes(rel, heapBlk, nblocks, &dummy, FSMCreationThreshold))
 		/* No FSM to update and no local map either */
 		return;
 
@@ -311,8 +302,7 @@ FSMClearLocalMap(void)
 	if (FSM_LOCAL_MAP_EXISTS)
 	{
 		fsm_local_map.nblocks = 0;
-		memset(&fsm_local_map.map, FSM_LOCAL_NOT_AVAIL,
-			   sizeof(fsm_local_map.map));
+		fsm_local_map.map = 0;
 	}
 }
 
@@ -322,7 +312,7 @@ FSMClearLocalMap(void)
  */
 void
 XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk,
-							Size spaceAvail)
+							Size spaceAvail, BlockNumber FSMCreationThreshold)
 {
 	int			new_cat = fsm_space_avail_to_cat(spaceAvail);
 	FSMAddress	addr;
@@ -333,7 +323,7 @@ XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk,
 	bool		write_to_fsm;
 
 	/* This is meant to mirror the logic in fsm_allow_writes() */
-	if (heapBlk >= HEAP_FSM_CREATION_THRESHOLD)
+	if (heapBlk >= FSMCreationThreshold)
 		write_to_fsm = true;
 	else
 	{
@@ -343,14 +333,7 @@ XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk,
 		if (smgrexists(smgr, FSM_FORKNUM))
 			write_to_fsm = true;
 		else
-		{
-			BlockNumber heap_nblocks = smgrnblocks(smgr, MAIN_FORKNUM);
-
-			if (heap_nblocks > HEAP_FSM_CREATION_THRESHOLD)
-				write_to_fsm = true;
-			else
-				write_to_fsm = false;
-		}
+			write_to_fsm = false;
 	}
 
 	if (!write_to_fsm)
@@ -1058,7 +1041,7 @@ fsm_vacuum_page(Relation rel, FSMAddress addr,
 
 /*
  * For heaps, we prevent creation of the FSM unless the number of pages
- * exceeds HEAP_FSM_CREATION_THRESHOLD.  For tables that don't already have
+ * exceeds the given threshold.  For tables that don't already have
  * a FSM, this will save an inode and a few kB of space.
  *
  * XXX The API is a little awkward -- if the caller passes a valid nblocks
@@ -1069,16 +1052,12 @@ fsm_vacuum_page(Relation rel, FSMAddress addr,
  */
 static bool
 fsm_allow_writes(Relation rel, BlockNumber heapblk,
-				 BlockNumber nblocks, BlockNumber *get_nblocks)
+				 BlockNumber nblocks, BlockNumber *get_nblocks,
+				 BlockNumber FSMCreationThreshold)
 {
 	bool		skip_get_nblocks;
 
-	if (heapblk >= HEAP_FSM_CREATION_THRESHOLD)
-		return true;
-
-	/* Non-heap rels can always create a FSM. */
-	if (rel->rd_rel->relkind != RELKIND_RELATION &&
-		rel->rd_rel->relkind != RELKIND_TOASTVALUE)
+	if (heapblk >= FSMCreationThreshold)
 		return true;
 
 	/*
@@ -1089,7 +1068,7 @@ fsm_allow_writes(Relation rel, BlockNumber heapblk,
 	 */
 	if (nblocks != InvalidBlockNumber)
 	{
-		if (nblocks > HEAP_FSM_CREATION_THRESHOLD)
+		if (nblocks > FSMCreationThreshold)
 			return true;
 		else
 			skip_get_nblocks = true;
@@ -1097,7 +1076,7 @@ fsm_allow_writes(Relation rel, BlockNumber heapblk,
 	else
 	{
 		if (rel->rd_rel->relpages != InvalidBlockNumber &&
-			rel->rd_rel->relpages > HEAP_FSM_CREATION_THRESHOLD)
+			rel->rd_rel->relpages > FSMCreationThreshold)
 			return true;
 		else
 			skip_get_nblocks = false;
@@ -1112,7 +1091,7 @@ fsm_allow_writes(Relation rel, BlockNumber heapblk,
 
 	/* last resort */
 	*get_nblocks = RelationGetNumberOfBlocks(rel);
-	if (*get_nblocks > HEAP_FSM_CREATION_THRESHOLD)
+	if (*get_nblocks > FSMCreationThreshold)
 		return true;
 	else
 		return false;
@@ -1135,6 +1114,9 @@ fsm_local_set(Relation rel, BlockNumber cur_nblocks)
 	/* The local map must not be set already. */
 	Assert(!FSM_LOCAL_MAP_EXISTS);
 
+	/* The relation's number of blocks must fit in the local map */
+	Assert(cur_nblocks <= sizeof(fsm_local_map.map));
+
 	/*
 	 * Starting at the current last block in the relation and working
 	 * backwards, mark alternating blocks as available.
@@ -1142,7 +1124,7 @@ fsm_local_set(Relation rel, BlockNumber cur_nblocks)
 	blkno = cur_nblocks - 1;
 	while (true)
 	{
-		fsm_local_map.map[blkno] = FSM_LOCAL_AVAIL;
+		FSM_LOCAL_MAP_SET_AVAIL(blkno);
 		if (blkno >= 2)
 			blkno -= 2;
 		else
@@ -1156,7 +1138,7 @@ fsm_local_set(Relation rel, BlockNumber cur_nblocks)
 	cached_target_block = RelationGetTargetBlock(rel);
 	if (cached_target_block != InvalidBlockNumber &&
 		cached_target_block < cur_nblocks)
-		fsm_local_map.map[cached_target_block] = FSM_LOCAL_NOT_AVAIL;
+		FSM_LOCAL_MAP_SET_UNAVAIL(cached_target_block);
 }
 
 /*
@@ -1179,7 +1161,7 @@ fsm_local_search(void)
 	do
 	{
 		target_block--;
-		if (fsm_local_map.map[target_block] == FSM_LOCAL_AVAIL)
+		if (FSM_LOCAL_MAP_IS_AVAIL(target_block))
 			return target_block;
 	} while (target_block > 0);
 
diff --git a/src/backend/storage/freespace/indexfsm.c b/src/backend/storage/freespace/indexfsm.c
index 9d8f43d373..50bcafb6a5 100644
--- a/src/backend/storage/freespace/indexfsm.c
+++ b/src/backend/storage/freespace/indexfsm.c
@@ -25,6 +25,9 @@
 #include "storage/freespace.h"
 #include "storage/indexfsm.h"
 
+/* Indexes using these routines can always create a FSM. */
+#define INDEX_FSM_CREATION_THRESHOLD 0
+
 /*
  * Exported routines
  */
@@ -37,7 +40,7 @@
 BlockNumber
 GetFreeIndexPage(Relation rel)
 {
-	BlockNumber blkno = GetPageWithFreeSpace(rel, BLCKSZ / 2, true);
+	BlockNumber blkno = GetPageWithFreeSpace(rel, BLCKSZ / 2);
 
 	if (blkno != InvalidBlockNumber)
 		RecordUsedIndexPage(rel, blkno);
@@ -51,7 +54,8 @@ GetFreeIndexPage(Relation rel)
 void
 RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
 {
-	RecordPageWithFreeSpace(rel, freeBlock, BLCKSZ - 1, InvalidBlockNumber);
+	RecordPageWithFreeSpace(rel, freeBlock, BLCKSZ - 1, InvalidBlockNumber,
+							INDEX_FSM_CREATION_THRESHOLD);
 }
 
 
@@ -61,8 +65,8 @@ RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
 void
 RecordUsedIndexPage(Relation rel, BlockNumber usedBlock)
 {
-	RecordPageWithFreeSpace(rel, usedBlock, 0, InvalidBlockNumber);
-}
+	RecordPageWithFreeSpace(rel, usedBlock, 0, InvalidBlockNumber,
+							INDEX_FSM_CREATION_THRESHOLD);}
 
 /*
  * IndexFreeSpaceMapVacuum - scan and fix any inconsistencies in the FSM
diff --git a/src/bin/pg_upgrade/relfilenode.c b/src/bin/pg_upgrade/relfilenode.c
index dd3c8cefe4..e3c844acd9 100644
--- a/src/bin/pg_upgrade/relfilenode.c
+++ b/src/bin/pg_upgrade/relfilenode.c
@@ -13,8 +13,9 @@
 
 #include <sys/stat.h>
 #include "catalog/pg_class_d.h"
+#include "access/heap_fe.h"
 #include "access/transam.h"
-#include "storage/freespace.h"
+#include "storage/block.h"
 
 
 static void transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace);
@@ -293,6 +294,7 @@ new_cluster_needs_fsm(FileNameMap *map)
 {
 	char		old_primary_file[MAXPGPATH];
 	struct stat statbuf;
+	BlockNumber FSMCreationThreshold;
 
 	/* fsm/vm files added in PG 8.4 */
 	Assert(GET_MAJOR_VERSION(old_cluster.major_version) >= 804);
@@ -301,9 +303,12 @@ new_cluster_needs_fsm(FileNameMap *map)
 		  GET_MAJOR_VERSION(new_cluster.major_version) >= 1200))
 		return true;
 
-	/* Always transfer FSMs of non-heap relations. */
-	if (map->relkind != RELKIND_RELATION &&
-		map->relkind != RELKIND_TOASTVALUE)
+	/* If other table types need this treatment, include their threshold. */
+	if (map->relkind == RELKIND_RELATION ||
+		map->relkind == RELKIND_TOASTVALUE)
+		FSMCreationThreshold = HEAP_FSM_CREATION_THRESHOLD;
+	else
+		/* Always transfer FSMs of other kinds of relations. */
 		return true;
 
 	/*
@@ -311,7 +316,7 @@ new_cluster_needs_fsm(FileNameMap *map)
 	 * threshold, we will transfer a FSM when we don't need to, but this is
 	 * harmless.
 	 */
-	if (map->relpages > HEAP_FSM_CREATION_THRESHOLD)
+	if (map->relpages > FSMCreationThreshold)
 		return true;
 
 	/* Determine path of the primary file. */
@@ -334,7 +339,7 @@ new_cluster_needs_fsm(FileNameMap *map)
 		/* Keep compiler quiet. */
 		return false;
 	}
-	else if (statbuf.st_size > HEAP_FSM_CREATION_THRESHOLD * BLCKSZ)
+	else if (statbuf.st_size > FSMCreationThreshold * BLCKSZ)
 		return true;
 	else
 		return false;
diff --git a/src/include/access/brin_pageops.h b/src/include/access/brin_pageops.h
index 30d1761fc7..aff78c059b 100644
--- a/src/include/access/brin_pageops.h
+++ b/src/include/access/brin_pageops.h
@@ -13,6 +13,9 @@
 
 #include "access/brin_revmap.h"
 
+/* BRIN indexes can always create a FSM. */
+#define BRIN_FSM_CREATION_THRESHOLD 0
+
 extern bool brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
 			  BrinRevmap *revmap, BlockNumber heapBlk,
 			  Buffer oldbuf, OffsetNumber oldoff,
diff --git a/src/include/access/heap_fe.h b/src/include/access/heap_fe.h
new file mode 100644
index 0000000000..558c6e5a33
--- /dev/null
+++ b/src/include/access/heap_fe.h
@@ -0,0 +1,20 @@
+/*-------------------------------------------------------------------------
+ *
+ * heap_fe.h
+ *	  POSTGRES heap access method constants used by front-end code.
+ *
+ *
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/access/heap_fe.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef HEAP_FE_H
+#define HEAP_FE_H
+
+/* Only create the FSM if the heap has greater than this many blocks */
+#define HEAP_FSM_CREATION_THRESHOLD 4
+
+#endif							/* HEAP_FE_H */
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index 77e5e603b0..1356d4688e 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -14,6 +14,7 @@
 #ifndef HEAPAM_H
 #define HEAPAM_H
 
+#include "access/heap_fe.h"
 #include "access/relation.h"	/* for backward compatibility */
 #include "access/relscan.h"
 #include "access/sdir.h"
diff --git a/src/include/storage/freespace.h b/src/include/storage/freespace.h
index dbaae651c5..3b433cf4f6 100644
--- a/src/include/storage/freespace.h
+++ b/src/include/storage/freespace.h
@@ -18,22 +18,21 @@
 #include "storage/relfilenode.h"
 #include "utils/relcache.h"
 
-/* Only create the FSM if the heap has greater than this many blocks */
-#define HEAP_FSM_CREATION_THRESHOLD 4
-
 /* prototypes for public functions in freespace.c */
 extern Size GetRecordedFreeSpace(Relation rel, BlockNumber heapBlk);
-extern BlockNumber GetPageWithFreeSpace(Relation rel, Size spaceNeeded,
-					 bool check_fsm_only);
+extern BlockNumber GetPageWithFreeSpace(Relation rel, Size spaceNeeded);
+extern BlockNumber GetAlternatePage(Relation rel, BlockNumber FSMCreationThreshold);
 extern BlockNumber RecordAndGetPageWithFreeSpace(Relation rel,
 							  BlockNumber oldPage,
 							  Size oldSpaceAvail,
-							  Size spaceNeeded);
+							  Size spaceNeeded,
+							  BlockNumber FSMCreationThreshold);
 extern void RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk,
-						Size spaceAvail, BlockNumber nblocks);
+						Size spaceAvail, BlockNumber nblocks,
+						BlockNumber FSMCreationThreshold);
 extern void FSMClearLocalMap(void);
 extern void XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk,
-							Size spaceAvail);
+							Size spaceAvail, BlockNumber FSMCreationThreshold);
 
 extern void FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks);
 extern void FreeSpaceMapVacuum(Relation rel);
