*** a/src/backend/access/gin/ginfast.c
--- b/src/backend/access/gin/ginfast.c
***************
*** 21,26 ****
--- 21,27 ----
  #include "access/gin_private.h"
  #include "commands/vacuum.h"
  #include "miscadmin.h"
+ #include "storage/indexfsm.h"
  #include "utils/memutils.h"
  #include "utils/rel.h"
  
***************
*** 434,440 **** ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
--- 435,453 ----
  	END_CRIT_SECTION();
  
  	if (needCleanup)
+ 	{
  		ginInsertCleanup(ginstate, false, NULL);
+ 
+ 		/*
+ 		 * Vacuum the FSM to make the deleted list pages available for re-use.
+ 		 *
+ 		 * gininsertCleanup marked them as free in the FSM by calling
+ 		 * RecordFreeIndexPage, but that only updates the bottom FSM level.
+ 		 * Since GetFreeIndexPage scans from the top, they won't be visible
+ 		 * for reuse until the upper levels have been updated.
+ 		 */
+ 		IndexFreeSpaceMapVacuum(index);
+ 	}
  }
  
  /*
***************
*** 599,608 **** shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
  			}
  		}
  
  		for (i = 0; i < data.ndeleted; i++)
  			UnlockReleaseBuffer(buffers[i]);
! 
! 		END_CRIT_SECTION();
  	} while (blknoToDelete != newHead);
  
  	return false;
--- 612,625 ----
  			}
  		}
  
+ 		END_CRIT_SECTION();
+ 
  		for (i = 0; i < data.ndeleted; i++)
+ 		{
+ 			BlockNumber blkno = BufferGetBlockNumber(buffers[i]);
  			UnlockReleaseBuffer(buffers[i]);
! 			RecordFreeIndexPage(index, blkno);
! 		}
  	} while (blknoToDelete != newHead);
  
  	return false;
