Skip to content

Commit b7cc647

Browse files
committed
Make smgr access for a BufferManagerRelation safer in relcache inval
Currently there's no bug, because we have no code path where we invalidate relcache entries where it'd cause a problem. But it's more robust to do it this way in case we introduce such a path later, as some Postgres forks reportedly already have. Author: Daniil Davydov <[email protected]> Reviewed-by: Stepan Neretin <[email protected]> Discussion: https://postgr.es/m/CAJDiXgj3FNzAhV+jjPqxMs3jz=OgPohsoXFj_fh-L+nS+13CKQ@mail.gmail.com
1 parent 9fd29d7 commit b7cc647

File tree

3 files changed

+44
-40
lines changed

3 files changed

+44
-40
lines changed

src/backend/storage/buffer/bufmgr.c

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -883,14 +883,11 @@ ExtendBufferedRelBy(BufferManagerRelation bmr,
883883
uint32 *extended_by)
884884
{
885885
Assert((bmr.rel != NULL) != (bmr.smgr != NULL));
886-
Assert(bmr.smgr == NULL || bmr.relpersistence != 0);
886+
Assert(bmr.smgr == NULL || bmr.relpersistence != '\0');
887887
Assert(extend_by > 0);
888888

889-
if (bmr.smgr == NULL)
890-
{
891-
bmr.smgr = RelationGetSmgr(bmr.rel);
889+
if (bmr.relpersistence == '\0')
892890
bmr.relpersistence = bmr.rel->rd_rel->relpersistence;
893-
}
894891

895892
return ExtendBufferedRelCommon(bmr, fork, strategy, flags,
896893
extend_by, InvalidBlockNumber,
@@ -919,30 +916,27 @@ ExtendBufferedRelTo(BufferManagerRelation bmr,
919916
Buffer buffers[64];
920917

921918
Assert((bmr.rel != NULL) != (bmr.smgr != NULL));
922-
Assert(bmr.smgr == NULL || bmr.relpersistence != 0);
919+
Assert(bmr.smgr == NULL || bmr.relpersistence != '\0');
923920
Assert(extend_to != InvalidBlockNumber && extend_to > 0);
924921

925-
if (bmr.smgr == NULL)
926-
{
927-
bmr.smgr = RelationGetSmgr(bmr.rel);
922+
if (bmr.relpersistence == '\0')
928923
bmr.relpersistence = bmr.rel->rd_rel->relpersistence;
929-
}
930924

931925
/*
932926
* If desired, create the file if it doesn't exist. If
933927
* smgr_cached_nblocks[fork] is positive then it must exist, no need for
934928
* an smgrexists call.
935929
*/
936930
if ((flags & EB_CREATE_FORK_IF_NEEDED) &&
937-
(bmr.smgr->smgr_cached_nblocks[fork] == 0 ||
938-
bmr.smgr->smgr_cached_nblocks[fork] == InvalidBlockNumber) &&
939-
!smgrexists(bmr.smgr, fork))
931+
(BMR_GET_SMGR(bmr)->smgr_cached_nblocks[fork] == 0 ||
932+
BMR_GET_SMGR(bmr)->smgr_cached_nblocks[fork] == InvalidBlockNumber) &&
933+
!smgrexists(BMR_GET_SMGR(bmr), fork))
940934
{
941935
LockRelationForExtension(bmr.rel, ExclusiveLock);
942936

943937
/* recheck, fork might have been created concurrently */
944-
if (!smgrexists(bmr.smgr, fork))
945-
smgrcreate(bmr.smgr, fork, flags & EB_PERFORMING_RECOVERY);
938+
if (!smgrexists(BMR_GET_SMGR(bmr), fork))
939+
smgrcreate(BMR_GET_SMGR(bmr), fork, flags & EB_PERFORMING_RECOVERY);
946940

947941
UnlockRelationForExtension(bmr.rel, ExclusiveLock);
948942
}
@@ -952,13 +946,13 @@ ExtendBufferedRelTo(BufferManagerRelation bmr,
952946
* kernel.
953947
*/
954948
if (flags & EB_CLEAR_SIZE_CACHE)
955-
bmr.smgr->smgr_cached_nblocks[fork] = InvalidBlockNumber;
949+
BMR_GET_SMGR(bmr)->smgr_cached_nblocks[fork] = InvalidBlockNumber;
956950

957951
/*
958952
* Estimate how many pages we'll need to extend by. This avoids acquiring
959953
* unnecessarily many victim buffers.
960954
*/
961-
current_size = smgrnblocks(bmr.smgr, fork);
955+
current_size = smgrnblocks(BMR_GET_SMGR(bmr), fork);
962956

963957
/*
964958
* Since no-one else can be looking at the page contents yet, there is no
@@ -1002,7 +996,7 @@ ExtendBufferedRelTo(BufferManagerRelation bmr,
1002996
if (buffer == InvalidBuffer)
1003997
{
1004998
Assert(extended_by == 0);
1005-
buffer = ReadBuffer_common(bmr.rel, bmr.smgr, bmr.relpersistence,
999+
buffer = ReadBuffer_common(bmr.rel, BMR_GET_SMGR(bmr), bmr.relpersistence,
10061000
fork, extend_to - 1, mode, strategy);
10071001
}
10081002

@@ -2540,10 +2534,10 @@ ExtendBufferedRelCommon(BufferManagerRelation bmr,
25402534
BlockNumber first_block;
25412535

25422536
TRACE_POSTGRESQL_BUFFER_EXTEND_START(fork,
2543-
bmr.smgr->smgr_rlocator.locator.spcOid,
2544-
bmr.smgr->smgr_rlocator.locator.dbOid,
2545-
bmr.smgr->smgr_rlocator.locator.relNumber,
2546-
bmr.smgr->smgr_rlocator.backend,
2537+
BMR_GET_SMGR(bmr)->smgr_rlocator.locator.spcOid,
2538+
BMR_GET_SMGR(bmr)->smgr_rlocator.locator.dbOid,
2539+
BMR_GET_SMGR(bmr)->smgr_rlocator.locator.relNumber,
2540+
BMR_GET_SMGR(bmr)->smgr_rlocator.backend,
25472541
extend_by);
25482542

25492543
if (bmr.relpersistence == RELPERSISTENCE_TEMP)
@@ -2557,10 +2551,10 @@ ExtendBufferedRelCommon(BufferManagerRelation bmr,
25572551
*extended_by = extend_by;
25582552

25592553
TRACE_POSTGRESQL_BUFFER_EXTEND_DONE(fork,
2560-
bmr.smgr->smgr_rlocator.locator.spcOid,
2561-
bmr.smgr->smgr_rlocator.locator.dbOid,
2562-
bmr.smgr->smgr_rlocator.locator.relNumber,
2563-
bmr.smgr->smgr_rlocator.backend,
2554+
BMR_GET_SMGR(bmr)->smgr_rlocator.locator.spcOid,
2555+
BMR_GET_SMGR(bmr)->smgr_rlocator.locator.dbOid,
2556+
BMR_GET_SMGR(bmr)->smgr_rlocator.locator.relNumber,
2557+
BMR_GET_SMGR(bmr)->smgr_rlocator.backend,
25642558
*extended_by,
25652559
first_block);
25662560

@@ -2626,9 +2620,9 @@ ExtendBufferedRelShared(BufferManagerRelation bmr,
26262620
* kernel.
26272621
*/
26282622
if (flags & EB_CLEAR_SIZE_CACHE)
2629-
bmr.smgr->smgr_cached_nblocks[fork] = InvalidBlockNumber;
2623+
BMR_GET_SMGR(bmr)->smgr_cached_nblocks[fork] = InvalidBlockNumber;
26302624

2631-
first_block = smgrnblocks(bmr.smgr, fork);
2625+
first_block = smgrnblocks(BMR_GET_SMGR(bmr), fork);
26322626

26332627
/*
26342628
* Now that we have the accurate relation size, check if the caller wants
@@ -2666,7 +2660,7 @@ ExtendBufferedRelShared(BufferManagerRelation bmr,
26662660
ereport(ERROR,
26672661
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
26682662
errmsg("cannot extend relation %s beyond %u blocks",
2669-
relpath(bmr.smgr->smgr_rlocator, fork).str,
2663+
relpath(BMR_GET_SMGR(bmr)->smgr_rlocator, fork).str,
26702664
MaxBlockNumber)));
26712665

26722666
/*
@@ -2688,7 +2682,8 @@ ExtendBufferedRelShared(BufferManagerRelation bmr,
26882682
ResourceOwnerEnlarge(CurrentResourceOwner);
26892683
ReservePrivateRefCountEntry();
26902684

2691-
InitBufferTag(&tag, &bmr.smgr->smgr_rlocator.locator, fork, first_block + i);
2685+
InitBufferTag(&tag, &BMR_GET_SMGR(bmr)->smgr_rlocator.locator, fork,
2686+
first_block + i);
26922687
hash = BufTableHashCode(&tag);
26932688
partition_lock = BufMappingPartitionLock(hash);
26942689

@@ -2730,7 +2725,7 @@ ExtendBufferedRelShared(BufferManagerRelation bmr,
27302725
ereport(ERROR,
27312726
(errmsg("unexpected data beyond EOF in block %u of relation \"%s\"",
27322727
existing_hdr->tag.blockNum,
2733-
relpath(bmr.smgr->smgr_rlocator, fork).str)));
2728+
relpath(BMR_GET_SMGR(bmr)->smgr_rlocator, fork).str)));
27342729

27352730
/*
27362731
* We *must* do smgr[zero]extend before succeeding, else the page
@@ -2787,7 +2782,7 @@ ExtendBufferedRelShared(BufferManagerRelation bmr,
27872782
*
27882783
* We don't need to set checksum for all-zero pages.
27892784
*/
2790-
smgrzeroextend(bmr.smgr, fork, first_block, extend_by, false);
2785+
smgrzeroextend(BMR_GET_SMGR(bmr), fork, first_block, extend_by, false);
27912786

27922787
/*
27932788
* Release the file-extension lock; it's now OK for someone else to extend

src/backend/storage/buffer/localbuf.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "utils/guc_hooks.h"
2626
#include "utils/memdebug.h"
2727
#include "utils/memutils.h"
28+
#include "utils/rel.h"
2829
#include "utils/resowner.h"
2930

3031

@@ -372,7 +373,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr,
372373
MemSet(buf_block, 0, BLCKSZ);
373374
}
374375

375-
first_block = smgrnblocks(bmr.smgr, fork);
376+
first_block = smgrnblocks(BMR_GET_SMGR(bmr), fork);
376377

377378
if (extend_upto != InvalidBlockNumber)
378379
{
@@ -391,7 +392,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr,
391392
ereport(ERROR,
392393
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
393394
errmsg("cannot extend relation %s beyond %u blocks",
394-
relpath(bmr.smgr->smgr_rlocator, fork).str,
395+
relpath(BMR_GET_SMGR(bmr)->smgr_rlocator, fork).str,
395396
MaxBlockNumber)));
396397

397398
for (uint32 i = 0; i < extend_by; i++)
@@ -408,7 +409,8 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr,
408409
/* in case we need to pin an existing buffer below */
409410
ResourceOwnerEnlarge(CurrentResourceOwner);
410411

411-
InitBufferTag(&tag, &bmr.smgr->smgr_rlocator.locator, fork, first_block + i);
412+
InitBufferTag(&tag, &BMR_GET_SMGR(bmr)->smgr_rlocator.locator, fork,
413+
first_block + i);
412414

413415
hresult = (LocalBufferLookupEnt *)
414416
hash_search(LocalBufHash, &tag, HASH_ENTER, &found);
@@ -456,7 +458,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr,
456458
io_start = pgstat_prepare_io_time(track_io_timing);
457459

458460
/* actually extend relation */
459-
smgrzeroextend(bmr.smgr, fork, first_block, extend_by, false);
461+
smgrzeroextend(BMR_GET_SMGR(bmr), fork, first_block, extend_by, false);
460462

461463
pgstat_count_io_op_time(IOOBJECT_TEMP_RELATION, IOCONTEXT_NORMAL, IOOP_EXTEND,
462464
io_start, 1, extend_by * BLCKSZ);

src/include/storage/bufmgr.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,11 @@ typedef struct SMgrRelationData *SMgrRelation;
9898

9999
/*
100100
* Some functions identify relations either by relation or smgr +
101-
* relpersistence. Used via the BMR_REL()/BMR_SMGR() macros below. This
102-
* allows us to use the same function for both recovery and normal operation.
101+
* relpersistence, initialized via the BMR_REL()/BMR_SMGR() macros below.
102+
* This allows us to use the same function for both recovery and normal
103+
* operation. When BMR_REL is used, it's not valid to cache its rd_smgr here,
104+
* because our pointer would be obsolete in case of relcache invalidation.
105+
* For simplicity, use BMR_GET_SMGR to read the smgr.
103106
*/
104107
typedef struct BufferManagerRelation
105108
{
@@ -108,8 +111,12 @@ typedef struct BufferManagerRelation
108111
char relpersistence;
109112
} BufferManagerRelation;
110113

111-
#define BMR_REL(p_rel) ((BufferManagerRelation){.rel = p_rel})
112-
#define BMR_SMGR(p_smgr, p_relpersistence) ((BufferManagerRelation){.smgr = p_smgr, .relpersistence = p_relpersistence})
114+
#define BMR_REL(p_rel) \
115+
((BufferManagerRelation){.rel = p_rel})
116+
#define BMR_SMGR(p_smgr, p_relpersistence) \
117+
((BufferManagerRelation){.smgr = p_smgr, .relpersistence = p_relpersistence})
118+
#define BMR_GET_SMGR(bmr) \
119+
(RelationIsValid((bmr).rel) ? RelationGetSmgr((bmr).rel) : (bmr).smgr)
113120

114121
/* Zero out page if reading fails. */
115122
#define READ_BUFFERS_ZERO_ON_ERROR (1 << 0)

0 commit comments

Comments
 (0)