diff options
Diffstat (limited to 'src/backend/catalog/storage.c')
-rw-r--r-- | src/backend/catalog/storage.c | 44 |
1 files changed, 30 insertions, 14 deletions
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c index 5c76e7a39ba..3525a771af5 100644 --- a/src/backend/catalog/storage.c +++ b/src/backend/catalog/storage.c @@ -232,24 +232,24 @@ RelationTruncate(Relation rel, BlockNumber nblocks) { bool fsm; bool vm; - - /* Open it at the smgr level if not already done */ - RelationOpenSmgr(rel); + SMgrRelation reln; /* - * Make sure smgr_targblock etc aren't pointing somewhere past new end + * Make sure smgr_targblock etc aren't pointing somewhere past new end. + * (Note: don't rely on this reln pointer below here.) */ - rel->rd_smgr->smgr_targblock = InvalidBlockNumber; - rel->rd_smgr->smgr_fsm_nblocks = InvalidBlockNumber; - rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber; + reln = RelationGetSmgr(rel); + reln->smgr_targblock = InvalidBlockNumber; + reln->smgr_fsm_nblocks = InvalidBlockNumber; + reln->smgr_vm_nblocks = InvalidBlockNumber; /* Truncate the FSM first if it exists */ - fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM); + fsm = smgrexists(reln, FSM_FORKNUM); if (fsm) FreeSpaceMapTruncateRel(rel, nblocks); /* Truncate the visibility map too if it exists. */ - vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM); + vm = smgrexists(RelationGetSmgr(rel), VISIBILITYMAP_FORKNUM); if (vm) visibilitymap_truncate(rel, nblocks); @@ -312,7 +312,7 @@ RelationTruncate(Relation rel, BlockNumber nblocks) * longer exist after truncation is complete, and then truncate the * corresponding files on disk. */ - smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks); + smgrtruncate(RelationGetSmgr(rel), MAIN_FORKNUM, nblocks); /* We've done all the critical work, so checkpoints are OK now. */ MyProc->delayChkptEnd = false; @@ -324,6 +324,12 @@ RelationTruncate(Relation rel, BlockNumber nblocks) * Note that this requires that there is no dirty data in shared buffers. If * it's possible that there are, callers need to flush those using * e.g. FlushRelationBuffers(rel). + * + * Also note that this is frequently called via locutions such as + * RelationCopyStorage(RelationGetSmgr(rel), ...); + * That's safe only because we perform only smgr and WAL operations here. + * If we invoked anything else, a relcache flush could cause our SMgrRelation + * argument to become a dangling pointer. */ void RelationCopyStorage(SMgrRelation src, SMgrRelation dst, @@ -364,13 +370,23 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst, if (!PageIsVerifiedExtended(page, blkno, PIV_LOG_WARNING | PIV_REPORT_STAT)) + { + /* + * For paranoia's sake, capture the file path before invoking the + * ereport machinery. This guards against the possibility of a + * relcache flush caused by, e.g., an errcontext callback. + * (errcontext callbacks shouldn't be risking any such thing, but + * people have been known to forget that rule.) + */ + char *relpath = relpathbackend(src->smgr_rnode.node, + src->smgr_rnode.backend, + forkNum); + ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("invalid page in block %u of relation %s", - blkno, - relpathbackend(src->smgr_rnode.node, - src->smgr_rnode.backend, - forkNum)))); + blkno, relpath))); + } /* * WAL-log the copied page. Unfortunately we don't know what kind of a |