* themselves, as there could pointers to them in active use. See
* smgrrelease() and smgrreleaseall().
*
+ * NB: We need to hold interrupts across most of the functions in this file,
+ * as otherwise interrupt processing, e.g. due to a < ERROR elog/ereport, can
+ * trigger procsignal processing, which in turn can trigger
+ * smgrreleaseall(). Most of the relevant code is not reentrant. It seems
+ * better to put the HOLD_INTERRUPTS()/RESUME_INTERRUPTS() here, instead of
+ * trying to push them down to md.c where possible: For one, every smgr
+ * implementation would be vulnerable, for another, a good bit of smgr.c code
+ * itself is affected too. Eventually we might want a more targeted solution,
+ * allowing e.g. a networked smgr implementation to be interrupted, but many
+ * other, more complicated, problems would need to be fixed for that to be
+ * viable (e.g. smgr.c is often called with interrupts already held).
+ *
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
#include "access/xlogutils.h"
#include "lib/ilist.h"
+#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "storage/ipc.h"
#include "storage/md.h"
{
int i;
+ HOLD_INTERRUPTS();
+
for (i = 0; i < NSmgr; i++)
{
if (smgrsw[i].smgr_init)
smgrsw[i].smgr_init();
}
+ RESUME_INTERRUPTS();
+
/* register the shutdown proc */
on_proc_exit(smgrshutdown, 0);
}
{
int i;
+ HOLD_INTERRUPTS();
+
for (i = 0; i < NSmgr; i++)
{
if (smgrsw[i].smgr_shutdown)
smgrsw[i].smgr_shutdown();
}
+
+ RESUME_INTERRUPTS();
}
/*
Assert(RelFileNumberIsValid(rlocator.relNumber));
+ HOLD_INTERRUPTS();
+
if (SMgrRelationHash == NULL)
{
/* First time through: initialize the hash table */
smgrsw[reln->smgr_which].smgr_open(reln);
}
+ RESUME_INTERRUPTS();
+
return reln;
}
Assert(reln->pincount == 0);
+ HOLD_INTERRUPTS();
+
for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
smgrsw[reln->smgr_which].smgr_close(reln, forknum);
&(reln->smgr_rlocator),
HASH_REMOVE, NULL) == NULL)
elog(ERROR, "SMgrRelation hashtable corrupted");
+
+ RESUME_INTERRUPTS();
}
/*
void
smgrrelease(SMgrRelation reln)
{
+ HOLD_INTERRUPTS();
+
for (ForkNumber forknum = 0; forknum <= MAX_FORKNUM; forknum++)
{
smgrsw[reln->smgr_which].smgr_close(reln, forknum);
reln->smgr_cached_nblocks[forknum] = InvalidBlockNumber;
}
reln->smgr_targblock = InvalidBlockNumber;
+
+ RESUME_INTERRUPTS();
}
/*
{
dlist_mutable_iter iter;
+ /* seems unsafe to accept interrupts while in a dlist_foreach_modify() */
+ HOLD_INTERRUPTS();
+
/*
* Zap all unpinned SMgrRelations. We rely on smgrdestroy() to remove
* each one from the list.
smgrdestroy(rel);
}
+
+ RESUME_INTERRUPTS();
}
/*
if (SMgrRelationHash == NULL)
return;
+ /* seems unsafe to accept interrupts while iterating */
+ HOLD_INTERRUPTS();
+
hash_seq_init(&status, SMgrRelationHash);
while ((reln = (SMgrRelation) hash_seq_search(&status)) != NULL)
{
smgrrelease(reln);
}
+
+ RESUME_INTERRUPTS();
}
/*
bool
smgrexists(SMgrRelation reln, ForkNumber forknum)
{
- return smgrsw[reln->smgr_which].smgr_exists(reln, forknum);
+ bool ret;
+
+ HOLD_INTERRUPTS();
+ ret = smgrsw[reln->smgr_which].smgr_exists(reln, forknum);
+ RESUME_INTERRUPTS();
+
+ return ret;
}
/*
void
smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
{
+ HOLD_INTERRUPTS();
smgrsw[reln->smgr_which].smgr_create(reln, forknum, isRedo);
+ RESUME_INTERRUPTS();
}
/*
FlushRelationsAllBuffers(rels, nrels);
+ HOLD_INTERRUPTS();
+
/*
* Sync the physical file(s).
*/
smgrsw[which].smgr_immedsync(rels[i], forknum);
}
}
+
+ RESUME_INTERRUPTS();
}
/*
if (nrels == 0)
return;
+ /*
+ * It would be unsafe to process interrupts between DropRelationBuffers()
+ * and unlinking the underlying files. This probably should be a critical
+ * section, but we're not there yet.
+ */
+ HOLD_INTERRUPTS();
+
/*
* Get rid of any remaining buffers for the relations. bufmgr will just
* drop them without bothering to write the contents.
}
pfree(rlocators);
+
+ RESUME_INTERRUPTS();
}
smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
const void *buffer, bool skipFsync)
{
+ HOLD_INTERRUPTS();
+
smgrsw[reln->smgr_which].smgr_extend(reln, forknum, blocknum,
buffer, skipFsync);
reln->smgr_cached_nblocks[forknum] = blocknum + 1;
else
reln->smgr_cached_nblocks[forknum] = InvalidBlockNumber;
+
+ RESUME_INTERRUPTS();
}
/*
smgrzeroextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
int nblocks, bool skipFsync)
{
+ HOLD_INTERRUPTS();
+
smgrsw[reln->smgr_which].smgr_zeroextend(reln, forknum, blocknum,
nblocks, skipFsync);
reln->smgr_cached_nblocks[forknum] = blocknum + nblocks;
else
reln->smgr_cached_nblocks[forknum] = InvalidBlockNumber;
+
+ RESUME_INTERRUPTS();
}
/*
smgrprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
int nblocks)
{
- return smgrsw[reln->smgr_which].smgr_prefetch(reln, forknum, blocknum, nblocks);
+ bool ret;
+
+ HOLD_INTERRUPTS();
+ ret = smgrsw[reln->smgr_which].smgr_prefetch(reln, forknum, blocknum, nblocks);
+ RESUME_INTERRUPTS();
+
+ return ret;
}
/*
smgrmaxcombine(SMgrRelation reln, ForkNumber forknum,
BlockNumber blocknum)
{
- return smgrsw[reln->smgr_which].smgr_maxcombine(reln, forknum, blocknum);
+ uint32 ret;
+
+ HOLD_INTERRUPTS();
+ ret = smgrsw[reln->smgr_which].smgr_maxcombine(reln, forknum, blocknum);
+ RESUME_INTERRUPTS();
+
+ return ret;
}
/*
smgrreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
void **buffers, BlockNumber nblocks)
{
+ HOLD_INTERRUPTS();
smgrsw[reln->smgr_which].smgr_readv(reln, forknum, blocknum, buffers,
nblocks);
+ RESUME_INTERRUPTS();
}
/*
smgrwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
const void **buffers, BlockNumber nblocks, bool skipFsync)
{
+ HOLD_INTERRUPTS();
smgrsw[reln->smgr_which].smgr_writev(reln, forknum, blocknum,
buffers, nblocks, skipFsync);
+ RESUME_INTERRUPTS();
}
/*
smgrwriteback(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
BlockNumber nblocks)
{
+ HOLD_INTERRUPTS();
smgrsw[reln->smgr_which].smgr_writeback(reln, forknum, blocknum,
nblocks);
+ RESUME_INTERRUPTS();
}
/*
if (result != InvalidBlockNumber)
return result;
+ HOLD_INTERRUPTS();
+
result = smgrsw[reln->smgr_which].smgr_nblocks(reln, forknum);
reln->smgr_cached_nblocks[forknum] = result;
+ RESUME_INTERRUPTS();
+
return result;
}
void
smgrregistersync(SMgrRelation reln, ForkNumber forknum)
{
+ HOLD_INTERRUPTS();
smgrsw[reln->smgr_which].smgr_registersync(reln, forknum);
+ RESUME_INTERRUPTS();
}
/*
void
smgrimmedsync(SMgrRelation reln, ForkNumber forknum)
{
+ HOLD_INTERRUPTS();
smgrsw[reln->smgr_which].smgr_immedsync(reln, forknum);
+ RESUME_INTERRUPTS();
}
/*