Skip to content

Commit 76733b3

Browse files
committed
Avoid using a fake relcache entry to own an SmgrRelation.
If an error occurs before we close the fake relcache entry, the the fake relcache entry will be destroyed by the SmgrRelation will survive until end of transaction. Its smgr_owner pointer ends up pointing to already-freed memory. The original reason for using a fake relcache entry here was to try to avoid reusing an SMgrRelation across a relevant invalidation. To avoid that problem, just call smgropen() again each time we need a reference to it. Hopefully someday we will come up with a more elegant approach, but accessing uninitialized memory is bad so let's do this for now. Dilip Kumar, reviewed by Andres Freund and Tom Lane. Report by Justin Pryzby. Discussion: http://postgr.es/m/[email protected] Discussion: http://postgr.es/m/CAFiTN-vSFeE6_W9z698XNtFROOA_nSqUXWqLcG0emob_kJ+dEQ@mail.gmail.com
1 parent 3d895bc commit 76733b3

File tree

2 files changed

+28
-38
lines changed

2 files changed

+28
-38
lines changed

src/backend/commands/dbcommands.c

+4-11
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,8 @@ ScanSourceDatabasePgClass(Oid tbid, Oid dbid, char *srcpath)
258258
Page page;
259259
List *rlocatorlist = NIL;
260260
LockRelId relid;
261-
Relation rel;
262261
Snapshot snapshot;
262+
SMgrRelation smgr;
263263
BufferAccessStrategy bstrategy;
264264

265265
/* Get pg_class relfilenumber. */
@@ -276,16 +276,9 @@ ScanSourceDatabasePgClass(Oid tbid, Oid dbid, char *srcpath)
276276
rlocator.dbOid = dbid;
277277
rlocator.relNumber = relfilenumber;
278278

279-
/*
280-
* We can't use a real relcache entry for a relation in some other
281-
* database, but since we're only going to access the fields related to
282-
* physical storage, a fake one is good enough. If we didn't do this and
283-
* used the smgr layer directly, we would have to worry about
284-
* invalidations.
285-
*/
286-
rel = CreateFakeRelcacheEntry(rlocator);
287-
nblocks = smgrnblocks(RelationGetSmgr(rel), MAIN_FORKNUM);
288-
FreeFakeRelcacheEntry(rel);
279+
smgr = smgropen(rlocator, InvalidBackendId);
280+
nblocks = smgrnblocks(smgr, MAIN_FORKNUM);
281+
smgrclose(smgr);
289282

290283
/* Use a buffer access strategy since this is a bulk read operation. */
291284
bstrategy = GetAccessStrategy(BAS_BULKREAD);

src/backend/storage/buffer/bufmgr.c

+24-27
Original file line numberDiff line numberDiff line change
@@ -487,9 +487,9 @@ static void FindAndDropRelationBuffers(RelFileLocator rlocator,
487487
ForkNumber forkNum,
488488
BlockNumber nForkBlock,
489489
BlockNumber firstDelBlock);
490-
static void RelationCopyStorageUsingBuffer(Relation src, Relation dst,
491-
ForkNumber forkNum,
492-
bool isunlogged);
490+
static void RelationCopyStorageUsingBuffer(RelFileLocator srclocator,
491+
RelFileLocator dstlocator,
492+
ForkNumber forkNum, bool permanent);
493493
static void AtProcExit_Buffers(int code, Datum arg);
494494
static void CheckForBufferLeaks(void);
495495
static int rlocator_comparator(const void *p1, const void *p2);
@@ -3701,8 +3701,9 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels)
37013701
* --------------------------------------------------------------------
37023702
*/
37033703
static void
3704-
RelationCopyStorageUsingBuffer(Relation src, Relation dst, ForkNumber forkNum,
3705-
bool permanent)
3704+
RelationCopyStorageUsingBuffer(RelFileLocator srclocator,
3705+
RelFileLocator dstlocator,
3706+
ForkNumber forkNum, bool permanent)
37063707
{
37073708
Buffer srcBuf;
37083709
Buffer dstBuf;
@@ -3722,7 +3723,8 @@ RelationCopyStorageUsingBuffer(Relation src, Relation dst, ForkNumber forkNum,
37223723
use_wal = XLogIsNeeded() && (permanent || forkNum == INIT_FORKNUM);
37233724

37243725
/* Get number of blocks in the source relation. */
3725-
nblocks = smgrnblocks(RelationGetSmgr(src), forkNum);
3726+
nblocks = smgrnblocks(smgropen(srclocator, InvalidBackendId),
3727+
forkNum);
37263728

37273729
/* Nothing to copy; just return. */
37283730
if (nblocks == 0)
@@ -3738,14 +3740,14 @@ RelationCopyStorageUsingBuffer(Relation src, Relation dst, ForkNumber forkNum,
37383740
CHECK_FOR_INTERRUPTS();
37393741

37403742
/* Read block from source relation. */
3741-
srcBuf = ReadBufferWithoutRelcache(src->rd_locator, forkNum, blkno,
3743+
srcBuf = ReadBufferWithoutRelcache(srclocator, forkNum, blkno,
37423744
RBM_NORMAL, bstrategy_src,
37433745
permanent);
37443746
LockBuffer(srcBuf, BUFFER_LOCK_SHARE);
37453747
srcPage = BufferGetPage(srcBuf);
37463748

37473749
/* Use P_NEW to extend the destination relation. */
3748-
dstBuf = ReadBufferWithoutRelcache(dst->rd_locator, forkNum, P_NEW,
3750+
dstBuf = ReadBufferWithoutRelcache(dstlocator, forkNum, P_NEW,
37493751
RBM_NORMAL, bstrategy_dst,
37503752
permanent);
37513753
LockBuffer(dstBuf, BUFFER_LOCK_EXCLUSIVE);
@@ -3783,24 +3785,13 @@ void
37833785
CreateAndCopyRelationData(RelFileLocator src_rlocator,
37843786
RelFileLocator dst_rlocator, bool permanent)
37853787
{
3786-
Relation src_rel;
3787-
Relation dst_rel;
3788+
RelFileLocatorBackend rlocator;
37883789
char relpersistence;
37893790

37903791
/* Set the relpersistence. */
37913792
relpersistence = permanent ?
37923793
RELPERSISTENCE_PERMANENT : RELPERSISTENCE_UNLOGGED;
37933794

3794-
/*
3795-
* We can't use a real relcache entry for a relation in some other
3796-
* database, but since we're only going to access the fields related to
3797-
* physical storage, a fake one is good enough. If we didn't do this and
3798-
* used the smgr layer directly, we would have to worry about
3799-
* invalidations.
3800-
*/
3801-
src_rel = CreateFakeRelcacheEntry(src_rlocator);
3802-
dst_rel = CreateFakeRelcacheEntry(dst_rlocator);
3803-
38043795
/*
38053796
* Create and copy all forks of the relation. During create database we
38063797
* have a separate cleanup mechanism which deletes complete database
@@ -3810,15 +3801,16 @@ CreateAndCopyRelationData(RelFileLocator src_rlocator,
38103801
RelationCreateStorage(dst_rlocator, relpersistence, false);
38113802

38123803
/* copy main fork. */
3813-
RelationCopyStorageUsingBuffer(src_rel, dst_rel, MAIN_FORKNUM, permanent);
3804+
RelationCopyStorageUsingBuffer(src_rlocator, dst_rlocator, MAIN_FORKNUM,
3805+
permanent);
38143806

38153807
/* copy those extra forks that exist */
38163808
for (ForkNumber forkNum = MAIN_FORKNUM + 1;
38173809
forkNum <= MAX_FORKNUM; forkNum++)
38183810
{
3819-
if (smgrexists(RelationGetSmgr(src_rel), forkNum))
3811+
if (smgrexists(smgropen(src_rlocator, InvalidBackendId), forkNum))
38203812
{
3821-
smgrcreate(RelationGetSmgr(dst_rel), forkNum, false);
3813+
smgrcreate(smgropen(dst_rlocator, InvalidBackendId), forkNum, false);
38223814

38233815
/*
38243816
* WAL log creation if the relation is persistent, or this is the
@@ -3828,14 +3820,19 @@ CreateAndCopyRelationData(RelFileLocator src_rlocator,
38283820
log_smgrcreate(&dst_rlocator, forkNum);
38293821

38303822
/* Copy a fork's data, block by block. */
3831-
RelationCopyStorageUsingBuffer(src_rel, dst_rel, forkNum,
3823+
RelationCopyStorageUsingBuffer(src_rlocator, dst_rlocator, forkNum,
38323824
permanent);
38333825
}
38343826
}
38353827

3836-
/* Release fake relcache entries. */
3837-
FreeFakeRelcacheEntry(src_rel);
3838-
FreeFakeRelcacheEntry(dst_rel);
3828+
/* close source and destination smgr if exists. */
3829+
rlocator.backend = InvalidBackendId;
3830+
3831+
rlocator.locator = src_rlocator;
3832+
smgrcloserellocator(rlocator);
3833+
3834+
rlocator.locator = dst_rlocator;
3835+
smgrcloserellocator(rlocator);
38393836
}
38403837

38413838
/* ---------------------------------------------------------------------

0 commit comments

Comments
 (0)