*** a/src/backend/storage/buffer/bufmgr.c
--- b/src/backend/storage/buffer/bufmgr.c
***************
*** 1834,1840 **** BufferGetTag(Buffer buffer, RelFileNode *rnode, ForkNumber *forknum,
   * written.)
   *
   * If the caller has an smgr reference for the buffer's relation, pass it
!  * as the second parameter.  If not, pass NULL.
   */
  static void
  FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
--- 1834,1843 ----
   * written.)
   *
   * If the caller has an smgr reference for the buffer's relation, pass it
!  * as the second parameter.  If not, pass NULL.  In the latter case, the
!  * relation will be marked as "transient" so that the corresponding
!  * kernel-level file descriptors are closed when the current transaction ends,
!  * if any.
   */
  static void
  FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
***************
*** 1856,1864 **** FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
  	errcontext.previous = error_context_stack;
  	error_context_stack = &errcontext;
  
! 	/* Find smgr relation for buffer */
  	if (reln == NULL)
  		reln = smgropen(buf->tag.rnode, InvalidBackendId);
  
  	TRACE_POSTGRESQL_BUFFER_FLUSH_START(buf->tag.forkNum,
  										buf->tag.blockNum,
--- 1859,1870 ----
  	errcontext.previous = error_context_stack;
  	error_context_stack = &errcontext;
  
! 	/* Find smgr relation for buffer, and mark it as transient */
  	if (reln == NULL)
+ 	{
  		reln = smgropen(buf->tag.rnode, InvalidBackendId);
+ 		smgrsettransient(reln);
+ 	}
  
  	TRACE_POSTGRESQL_BUFFER_FLUSH_START(buf->tag.forkNum,
  										buf->tag.blockNum,
*** a/src/backend/storage/file/fd.c
--- b/src/backend/storage/file/fd.c
***************
*** 125,136 **** static int	max_safe_fds = 32;	/* default if not changed */
  /* these are the assigned bits in fdstate below: */
  #define FD_TEMPORARY		(1 << 0)	/* T = delete when closed */
  #define FD_XACT_TEMPORARY	(1 << 1)	/* T = delete at eoXact */
  
  /*
!  * Flag to tell whether it's worth scanning VfdCache looking for temp files to
!  * close
   */
  static bool have_xact_temporary_files = false;
  
  typedef struct vfd
  {
--- 125,140 ----
  /* these are the assigned bits in fdstate below: */
  #define FD_TEMPORARY		(1 << 0)	/* T = delete when closed */
  #define FD_XACT_TEMPORARY	(1 << 1)	/* T = delete at eoXact */
+ #define FD_XACT_TRANSIENT	(1 << 2)	/* T = close (not delete) at aoXact,
+ 										 * but keep VFD */
  
  /*
!  * Global status flags
   */
+ /* are there FD_XACT_TEMPORARY files? */
  static bool have_xact_temporary_files = false;
+ /* are there FD_XACT_TRANSIENT files? */
+ static bool have_xact_transient_files = false;
  
  typedef struct vfd
  {
***************
*** 1027,1032 **** OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError)
--- 1031,1075 ----
  }
  
  /*
+  * Set the transient flag on a file
+  *
+  * This flag tells CleanupTempFiles to close the kernel-level file descriptor
+  * (but not the VFD itself) at end of transaction.
+  */
+ void
+ FileSetTransient(File file)
+ {
+ 	Vfd		  *vfdP;
+ 
+ 	Assert(FileIsValid(file));
+ 
+ 	vfdP = &VfdCache[file];
+ 	vfdP->fdstate |= FD_XACT_TRANSIENT;
+ 
+ 	have_xact_transient_files = true;
+ }
+ 
+ /*
+  * Close a file at the kernel level, but keep the VFD open
+  */
+ static void
+ FileKernelClose(File file)
+ {
+ 	Vfd		  *vfdP;
+ 
+ 	Assert(FileIsValid(file));
+ 
+ 	vfdP = &VfdCache[file];
+ 
+ 	if (!FileIsNotOpen(file))
+ 	{
+ 		if (close(vfdP->fd))
+ 			elog(ERROR, "could not close file \"%s\": %m", vfdP->fileName);
+ 		vfdP->fd = VFD_CLOSED;
+ 	}
+ }
+ 
+ /*
   * close a file when done with it
   */
  void
***************
*** 1819,1833 **** CleanupTempFiles(bool isProcExit)
  	 * Careful here: at proc_exit we need extra cleanup, not just
  	 * xact_temporary files.
  	 */
! 	if (isProcExit || have_xact_temporary_files)
  	{
  		Assert(FileIsNotOpen(0));		/* Make sure ring not corrupted */
  		for (i = 1; i < SizeVfdCache; i++)
  		{
  			unsigned short fdstate = VfdCache[i].fdstate;
  
! 			if ((fdstate & FD_TEMPORARY) && VfdCache[i].fileName != NULL)
  			{
  				/*
  				 * If we're in the process of exiting a backend process, close
  				 * all temporary files. Otherwise, only close temporary files
--- 1862,1878 ----
  	 * Careful here: at proc_exit we need extra cleanup, not just
  	 * xact_temporary files.
  	 */
! 	if (isProcExit || have_xact_temporary_files || have_xact_transient_files)
  	{
  		Assert(FileIsNotOpen(0));		/* Make sure ring not corrupted */
  		for (i = 1; i < SizeVfdCache; i++)
  		{
  			unsigned short fdstate = VfdCache[i].fdstate;
  
! 			if (VfdCache[i].fileName != NULL)
  			{
+ 				if (fdstate & FD_TEMPORARY)
+ 				{
  				/*
  				 * If we're in the process of exiting a backend process, close
  				 * all temporary files. Otherwise, only close temporary files
***************
*** 1844,1853 **** CleanupTempFiles(bool isProcExit)
--- 1889,1902 ----
  						 VfdCache[i].fileName);
  					FileClose(i);
  				}
+ 				}
+ 				else if (fdstate & FD_XACT_TRANSIENT)
+ 					FileKernelClose(i);
  			}
  		}
  
  		have_xact_temporary_files = false;
+ 		have_xact_transient_files = false;
  	}
  
  	/* Clean up "allocated" stdio files and dirs. */
*** a/src/backend/storage/smgr/md.c
--- b/src/backend/storage/smgr/md.c
***************
*** 288,293 **** mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
--- 288,296 ----
  
  	pfree(path);
  
+ 	if (reln->smgr_transient)
+ 		FileSetTransient(fd);
+ 
  	reln->md_fd[forkNum] = _fdvec_alloc();
  
  	reln->md_fd[forkNum]->mdfd_vfd = fd;
***************
*** 542,547 **** mdopen(SMgrRelation reln, ForkNumber forknum, ExtensionBehavior behavior)
--- 545,553 ----
  
  	pfree(path);
  
+ 	if (reln->smgr_transient)
+ 		FileSetTransient(fd);
+ 
  	reln->md_fd[forknum] = mdfd = _fdvec_alloc();
  
  	mdfd->mdfd_vfd = fd;
***************
*** 1556,1561 **** _mdfd_openseg(SMgrRelation reln, ForkNumber forknum, BlockNumber segno,
--- 1562,1570 ----
  	if (fd < 0)
  		return NULL;
  
+ 	if (reln->smgr_transient)
+ 		FileSetTransient(fd);
+ 
  	/* allocate an mdfdvec entry for it */
  	v = _fdvec_alloc();
  
*** a/src/backend/storage/smgr/smgr.c
--- b/src/backend/storage/smgr/smgr.c
***************
*** 165,170 **** smgropen(RelFileNode rnode, BackendId backend)
--- 165,171 ----
  		reln->smgr_targblock = InvalidBlockNumber;
  		reln->smgr_fsm_nblocks = InvalidBlockNumber;
  		reln->smgr_vm_nblocks = InvalidBlockNumber;
+ 		reln->smgr_transient = false;
  		reln->smgr_which = 0;	/* we only have md.c at present */
  
  		/* mark it not open */
***************
*** 176,181 **** smgropen(RelFileNode rnode, BackendId backend)
--- 177,195 ----
  }
  
  /*
+  * smgrsettransient -- mark an SMgrRelation object as transaction-bound
+  *
+  * The main effect of this is that all opened files are marked to be
+  * kernel-level closed (but not necessarily VFD-closed) when the current
+  * transaction ends.
+  */
+ void
+ smgrsettransient(SMgrRelation reln)
+ {
+ 	reln->smgr_transient = true;
+ }
+ 
+ /*
   * smgrsetowner() -- Establish a long-lived reference to an SMgrRelation object
   *
   * There can be only one owner at a time; this is sufficient since currently
*** a/src/include/storage/fd.h
--- b/src/include/storage/fd.h
***************
*** 61,66 **** extern int	max_files_per_process;
--- 61,67 ----
  /* Operations on virtual Files --- equivalent to Unix kernel file ops */
  extern File PathNameOpenFile(FileName fileName, int fileFlags, int fileMode);
  extern File OpenTemporaryFile(bool interXact);
+ extern void FileSetTransient(File file);
  extern void FileClose(File file);
  extern int	FilePrefetch(File file, off_t offset, int amount);
  extern int	FileRead(File file, char *buffer, int amount);
*** a/src/include/storage/smgr.h
--- b/src/include/storage/smgr.h
***************
*** 62,67 **** typedef struct SMgrRelationData
--- 62,68 ----
  	 * submodules.	Do not touch them from elsewhere.
  	 */
  	int			smgr_which;		/* storage manager selector */
+ 	bool		smgr_transient;	/* T if files are to be closed at EOXact */
  
  	/* for md.c; NULL for forks that are not open */
  	struct _MdfdVec *md_fd[MAX_FORKNUM + 1];
***************
*** 74,79 **** typedef SMgrRelationData *SMgrRelation;
--- 75,81 ----
  
  extern void smgrinit(void);
  extern SMgrRelation smgropen(RelFileNode rnode, BackendId backend);
+ extern void smgrsettransient(SMgrRelation reln);
  extern bool smgrexists(SMgrRelation reln, ForkNumber forknum);
  extern void smgrsetowner(SMgrRelation *owner, SMgrRelation reln);
  extern void smgrclose(SMgrRelation reln);
