]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Avoid using a fake relcache entry to own an SmgrRelation.
authorRobert Haas <rhaas@postgresql.org>
Fri, 12 Aug 2022 12:55:07 +0000 (08:55 -0400)
committerRobert Haas <rhaas@postgresql.org>
Fri, 12 Aug 2022 12:55:07 +0000 (08:55 -0400)
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/20220802175043.GA13682@telsasoft.com
Discussion: http://postgr.es/m/CAFiTN-vSFeE6_W9z698XNtFROOA_nSqUXWqLcG0emob_kJ+dEQ@mail.gmail.com

src/backend/commands/dbcommands.c
src/backend/storage/buffer/bufmgr.c

index 9a563b239c6f5724cad63e6ddcd409fa301d514d..6f836865e15f0e4d32020d52536fec5724d309f0 100644 (file)
@@ -257,8 +257,8 @@ ScanSourceDatabasePgClass(Oid tbid, Oid dbid, char *srcpath)
        Page            page;
        List       *rnodelist = NIL;
        LockRelId       relid;
-       Relation        rel;
        Snapshot        snapshot;
+       SMgrRelation    smgr;
        BufferAccessStrategy bstrategy;
 
        /* Get pg_class relfilenode. */
@@ -275,16 +275,9 @@ ScanSourceDatabasePgClass(Oid tbid, Oid dbid, char *srcpath)
        rnode.dbNode = dbid;
        rnode.relNode = relfilenode;
 
-       /*
-        * We can't use a real relcache entry for a relation in some other
-        * database, but since we're only going to access the fields related to
-        * physical storage, a fake one is good enough. If we didn't do this and
-        * used the smgr layer directly, we would have to worry about
-        * invalidations.
-        */
-       rel = CreateFakeRelcacheEntry(rnode);
-       nblocks = smgrnblocks(RelationGetSmgr(rel), MAIN_FORKNUM);
-       FreeFakeRelcacheEntry(rel);
+       smgr = smgropen(rnode, InvalidBackendId);
+       nblocks = smgrnblocks(smgr, MAIN_FORKNUM);
+       smgrclose(smgr);
 
        /* Use a buffer access strategy since this is a bulk read operation. */
        bstrategy = GetAccessStrategy(BAS_BULKREAD);
index 8aabf5991b0e78017823ffc25789150235d5e7f6..43d3c8caaa68893c7db39561550a3decde677933 100644 (file)
@@ -487,9 +487,9 @@ static void FindAndDropRelFileNodeBuffers(RelFileNode rnode,
                                                                                  ForkNumber forkNum,
                                                                                  BlockNumber nForkBlock,
                                                                                  BlockNumber firstDelBlock);
-static void RelationCopyStorageUsingBuffer(Relation src, Relation dst,
-                                                                                  ForkNumber forkNum,
-                                                                                  bool isunlogged);
+static void RelationCopyStorageUsingBuffer(RelFileNode srcnode,
+                                                                                  RelFileNode dstnode,
+                                                                                  ForkNumber forkNum, bool permanent);
 static void AtProcExit_Buffers(int code, Datum arg);
 static void CheckForBufferLeaks(void);
 static int     rnode_comparator(const void *p1, const void *p2);
@@ -3702,8 +3702,9 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels)
  * --------------------------------------------------------------------
  */
 static void
-RelationCopyStorageUsingBuffer(Relation src, Relation dst, ForkNumber forkNum,
-                                                          bool permanent)
+RelationCopyStorageUsingBuffer(RelFileNode srcnode,
+                                                          RelFileNode dstnode,
+                                                          ForkNumber forkNum, bool permanent)
 {
        Buffer          srcBuf;
        Buffer          dstBuf;
@@ -3723,7 +3724,8 @@ RelationCopyStorageUsingBuffer(Relation src, Relation dst, ForkNumber forkNum,
        use_wal = XLogIsNeeded() && (permanent || forkNum == INIT_FORKNUM);
 
        /* Get number of blocks in the source relation. */
-       nblocks = smgrnblocks(RelationGetSmgr(src), forkNum);
+       nblocks = smgrnblocks(smgropen(srcnode, InvalidBackendId),
+                                                 forkNum);
 
        /* Nothing to copy; just return. */
        if (nblocks == 0)
@@ -3739,14 +3741,14 @@ RelationCopyStorageUsingBuffer(Relation src, Relation dst, ForkNumber forkNum,
                CHECK_FOR_INTERRUPTS();
 
                /* Read block from source relation. */
-               srcBuf = ReadBufferWithoutRelcache(src->rd_node, forkNum, blkno,
+               srcBuf = ReadBufferWithoutRelcache(srcnode, forkNum, blkno,
                                                                                   RBM_NORMAL, bstrategy_src,
                                                                                   permanent);
                LockBuffer(srcBuf, BUFFER_LOCK_SHARE);
                srcPage = BufferGetPage(srcBuf);
 
                /* Use P_NEW to extend the destination relation. */
-               dstBuf = ReadBufferWithoutRelcache(dst->rd_node, forkNum, P_NEW,
+               dstBuf = ReadBufferWithoutRelcache(dstnode, forkNum, P_NEW,
                                                                                   RBM_NORMAL, bstrategy_dst,
                                                                                   permanent);
                LockBuffer(dstBuf, BUFFER_LOCK_EXCLUSIVE);
@@ -3784,24 +3786,13 @@ void
 CreateAndCopyRelationData(RelFileNode src_rnode, RelFileNode dst_rnode,
                                                  bool permanent)
 {
-       Relation        src_rel;
-       Relation        dst_rel;
+       RelFileNodeBackend rnode;
        char            relpersistence;
 
        /* Set the relpersistence. */
        relpersistence = permanent ?
                RELPERSISTENCE_PERMANENT : RELPERSISTENCE_UNLOGGED;
 
-       /*
-        * We can't use a real relcache entry for a relation in some other
-        * database, but since we're only going to access the fields related to
-        * physical storage, a fake one is good enough. If we didn't do this and
-        * used the smgr layer directly, we would have to worry about
-        * invalidations.
-        */
-       src_rel = CreateFakeRelcacheEntry(src_rnode);
-       dst_rel = CreateFakeRelcacheEntry(dst_rnode);
-
        /*
         * Create and copy all forks of the relation.  During create database we
         * have a separate cleanup mechanism which deletes complete database
@@ -3811,15 +3802,16 @@ CreateAndCopyRelationData(RelFileNode src_rnode, RelFileNode dst_rnode,
        RelationCreateStorage(dst_rnode, relpersistence, false);
 
        /* copy main fork. */
-       RelationCopyStorageUsingBuffer(src_rel, dst_rel, MAIN_FORKNUM, permanent);
+       RelationCopyStorageUsingBuffer(src_rnode, dst_rnode, MAIN_FORKNUM,
+                                                                  permanent);
 
        /* copy those extra forks that exist */
        for (ForkNumber forkNum = MAIN_FORKNUM + 1;
                 forkNum <= MAX_FORKNUM; forkNum++)
        {
-               if (smgrexists(RelationGetSmgr(src_rel), forkNum))
+               if (smgrexists(smgropen(src_rnode, InvalidBackendId), forkNum))
                {
-                       smgrcreate(RelationGetSmgr(dst_rel), forkNum, false);
+                       smgrcreate(smgropen(dst_rnode, InvalidBackendId), forkNum, false);
 
                        /*
                         * WAL log creation if the relation is persistent, or this is the
@@ -3829,14 +3821,19 @@ CreateAndCopyRelationData(RelFileNode src_rnode, RelFileNode dst_rnode,
                                log_smgrcreate(&dst_rnode, forkNum);
 
                        /* Copy a fork's data, block by block. */
-                       RelationCopyStorageUsingBuffer(src_rel, dst_rel, forkNum,
+                       RelationCopyStorageUsingBuffer(src_rnode, dst_rnode, forkNum,
                                                                                   permanent);
                }
        }
 
-       /* Release fake relcache entries. */
-       FreeFakeRelcacheEntry(src_rel);
-       FreeFakeRelcacheEntry(dst_rel);
+       /* close source and destination smgr if exists. */
+       rnode.backend = InvalidBackendId;
+
+       rnode.node = src_rnode;
+       smgrclosenode(rnode);
+
+       rnode.node = dst_rnode;
+       smgrclosenode(rnode);
 }
 
 /* ---------------------------------------------------------------------