aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/freespace/freespace.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2022-11-17 16:54:31 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2022-11-17 16:54:31 -0500
commite21856fd652ad1d6bfcc63bb427d29622359f948 (patch)
tree6069fab2135ee54a9b97e249f1ad91c3ed02ee82 /src/backend/storage/freespace/freespace.c
parent36dd0074af9f2abfbd480549e25c38fdc2631f6d (diff)
downloadpostgresql-e21856fd652ad1d6bfcc63bb427d29622359f948.tar.gz
postgresql-e21856fd652ad1d6bfcc63bb427d29622359f948.zip
Replace RelationOpenSmgr() with RelationGetSmgr().
This is a back-patch of the v15-era commit f10f0ae42 into older supported branches. The idea is to design out bugs in which an ill-timed relcache flush clears rel->rd_smgr partway through some code sequence that wasn't expecting that. We had another report today of a corner case that reliably crashes v14 under debug_discard_caches (nee CLOBBER_CACHE_ALWAYS), and therefore would crash once in a blue moon in the field. We're unlikely to get rid of all such code paths unless we adopt the more rigorous coding rules instituted by f10f0ae42. Therefore, even though this is a bit invasive, it's time to back-patch. Some comfort can be taken in the fact that f10f0ae42 has been in v15 for 16 months without problems. I left the RelationOpenSmgr macro present in the back branches, even though no core code should use it anymore, in order to not break third-party extensions in minor releases. Such extensions might opt to start using RelationGetSmgr instead, to reduce their code differential between v15 and earlier branches. This carries a hazard of failing to compile against headers from existing minor releases. However, once compiled the extension should work fine even with such releases, because RelationGetSmgr is a "static inline" function so it creates no link-time dependency. So depending on distribution practices, that might be an OK tradeoff. Per report from Spyridon Dimitrios Agathos. Original patch by Amul Sul. Discussion: https://postgr.es/m/CAFM5RaqdgyusQvmWkyPYaWMwoK5gigdtW-7HcgHgOeAw7mqJ_Q@mail.gmail.com Discussion: https://postgr.es/m/CANiYTQsU7yMFpQYnv=BrcRVqK_3U3mtAzAsJCaqtzsDHfsUbdQ@mail.gmail.com
Diffstat (limited to 'src/backend/storage/freespace/freespace.c')
-rw-r--r--src/backend/storage/freespace/freespace.c53
1 files changed, 31 insertions, 22 deletions
diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c
index c17b3f49dd0..f4c78dbfe4f 100644
--- a/src/backend/storage/freespace/freespace.c
+++ b/src/backend/storage/freespace/freespace.c
@@ -263,13 +263,11 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
uint16 first_removed_slot;
Buffer buf;
- RelationOpenSmgr(rel);
-
/*
* If no FSM has been created yet for this relation, there's nothing to
* truncate.
*/
- if (!smgrexists(rel->rd_smgr, FSM_FORKNUM))
+ if (!smgrexists(RelationGetSmgr(rel), FSM_FORKNUM))
return;
/* Get the location in the FSM of the first removed heap block */
@@ -314,12 +312,12 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
else
{
new_nfsmblocks = fsm_logical_to_physical(first_removed_address);
- if (smgrnblocks(rel->rd_smgr, FSM_FORKNUM) <= new_nfsmblocks)
+ if (smgrnblocks(RelationGetSmgr(rel), FSM_FORKNUM) <= new_nfsmblocks)
return; /* nothing to do; the FSM was already smaller */
}
/* Truncate the unused FSM pages, and send smgr inval message */
- smgrtruncate(rel->rd_smgr, FSM_FORKNUM, new_nfsmblocks);
+ smgrtruncate(RelationGetSmgr(rel), FSM_FORKNUM, new_nfsmblocks);
/*
* We might as well update the local smgr_fsm_nblocks setting.
@@ -546,8 +544,14 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
{
BlockNumber blkno = fsm_logical_to_physical(addr);
Buffer buf;
+ SMgrRelation reln;
- RelationOpenSmgr(rel);
+ /*
+ * Caution: re-using this smgr pointer could fail if the relcache entry
+ * gets closed. It's safe as long as we only do smgr-level operations
+ * between here and the last use of the pointer.
+ */
+ reln = RelationGetSmgr(rel);
/*
* If we haven't cached the size of the FSM yet, check it first. Also
@@ -555,18 +559,18 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
* value might be stale. (We send smgr inval messages on truncation, but
* not on extension.)
*/
- if (rel->rd_smgr->smgr_fsm_nblocks == InvalidBlockNumber ||
- blkno >= rel->rd_smgr->smgr_fsm_nblocks)
+ if (reln->smgr_fsm_nblocks == InvalidBlockNumber ||
+ blkno >= reln->smgr_fsm_nblocks)
{
- if (smgrexists(rel->rd_smgr, FSM_FORKNUM))
- rel->rd_smgr->smgr_fsm_nblocks = smgrnblocks(rel->rd_smgr,
- FSM_FORKNUM);
+ if (smgrexists(reln, FSM_FORKNUM))
+ reln->smgr_fsm_nblocks = smgrnblocks(reln,
+ FSM_FORKNUM);
else
- rel->rd_smgr->smgr_fsm_nblocks = 0;
+ reln->smgr_fsm_nblocks = 0;
}
/* Handle requests beyond EOF */
- if (blkno >= rel->rd_smgr->smgr_fsm_nblocks)
+ if (blkno >= reln->smgr_fsm_nblocks)
{
if (extend)
fsm_extend(rel, blkno + 1);
@@ -616,6 +620,7 @@ fsm_extend(Relation rel, BlockNumber fsm_nblocks)
{
BlockNumber fsm_nblocks_now;
PGAlignedBlock pg;
+ SMgrRelation reln;
PageInit((Page) pg.data, BLCKSZ, 0);
@@ -631,31 +636,35 @@ fsm_extend(Relation rel, BlockNumber fsm_nblocks)
*/
LockRelationForExtension(rel, ExclusiveLock);
- /* Might have to re-open if a cache flush happened */
- RelationOpenSmgr(rel);
+ /*
+ * Caution: re-using this smgr pointer could fail if the relcache entry
+ * gets closed. It's safe as long as we only do smgr-level operations
+ * between here and the last use of the pointer.
+ */
+ reln = RelationGetSmgr(rel);
/*
* Create the FSM file first if it doesn't exist. If smgr_fsm_nblocks is
* positive then it must exist, no need for an smgrexists call.
*/
- if ((rel->rd_smgr->smgr_fsm_nblocks == 0 ||
- rel->rd_smgr->smgr_fsm_nblocks == InvalidBlockNumber) &&
- !smgrexists(rel->rd_smgr, FSM_FORKNUM))
- smgrcreate(rel->rd_smgr, FSM_FORKNUM, false);
+ if ((reln->smgr_fsm_nblocks == 0 ||
+ reln->smgr_fsm_nblocks == InvalidBlockNumber) &&
+ !smgrexists(reln, FSM_FORKNUM))
+ smgrcreate(reln, FSM_FORKNUM, false);
- fsm_nblocks_now = smgrnblocks(rel->rd_smgr, FSM_FORKNUM);
+ fsm_nblocks_now = smgrnblocks(reln, FSM_FORKNUM);
while (fsm_nblocks_now < fsm_nblocks)
{
PageSetChecksumInplace((Page) pg.data, fsm_nblocks_now);
- smgrextend(rel->rd_smgr, FSM_FORKNUM, fsm_nblocks_now,
+ smgrextend(reln, FSM_FORKNUM, fsm_nblocks_now,
pg.data, false);
fsm_nblocks_now++;
}
/* Update local cache with the up-to-date size */
- rel->rd_smgr->smgr_fsm_nblocks = fsm_nblocks_now;
+ reln->smgr_fsm_nblocks = fsm_nblocks_now;
UnlockRelationForExtension(rel, ExclusiveLock);
}