Skip to content

Commit b6d8d20

Browse files
committed
Prevent race condition while reading relmapper file.
Contrary to the comment here, POSIX does not guarantee atomicity of a read(), if another process calls write() concurrently. Or at least Linux does not. Add locking to load_relmap_file() to avoid the race condition. Fixes bug #17064. Thanks to Alexander Lakhin for the report and test case. Backpatch-through: 9.6, all supported versions. Discussion: https://www.postgresql.org/message-id/17064-bb0d7904ef72add3@postgresql.org
1 parent f08722c commit b6d8d20

File tree

1 file changed

+20
-14
lines changed

1 file changed

+20
-14
lines changed

src/backend/utils/cache/relmapper.c

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ static void apply_map_update(RelMapFile *map, Oid relationId, Oid fileNode,
136136
bool add_okay);
137137
static void merge_map_updates(RelMapFile *map, const RelMapFile *updates,
138138
bool add_okay);
139-
static void load_relmap_file(bool shared);
139+
static void load_relmap_file(bool shared, bool lock_held);
140140
static void write_relmap_file(bool shared, RelMapFile *newmap,
141141
bool write_wal, bool send_sinval, bool preserve_files,
142142
Oid dbid, Oid tsid, const char *dbpath);
@@ -405,12 +405,12 @@ RelationMapInvalidate(bool shared)
405405
if (shared)
406406
{
407407
if (shared_map.magic == RELMAPPER_FILEMAGIC)
408-
load_relmap_file(true);
408+
load_relmap_file(true, false);
409409
}
410410
else
411411
{
412412
if (local_map.magic == RELMAPPER_FILEMAGIC)
413-
load_relmap_file(false);
413+
load_relmap_file(false, false);
414414
}
415415
}
416416

@@ -425,9 +425,9 @@ void
425425
RelationMapInvalidateAll(void)
426426
{
427427
if (shared_map.magic == RELMAPPER_FILEMAGIC)
428-
load_relmap_file(true);
428+
load_relmap_file(true, false);
429429
if (local_map.magic == RELMAPPER_FILEMAGIC)
430-
load_relmap_file(false);
430+
load_relmap_file(false, false);
431431
}
432432

433433
/*
@@ -612,7 +612,7 @@ RelationMapInitializePhase2(void)
612612
/*
613613
* Load the shared map file, die on error.
614614
*/
615-
load_relmap_file(true);
615+
load_relmap_file(true, false);
616616
}
617617

618618
/*
@@ -633,7 +633,7 @@ RelationMapInitializePhase3(void)
633633
/*
634634
* Load the local map file, die on error.
635635
*/
636-
load_relmap_file(false);
636+
load_relmap_file(false, false);
637637
}
638638

639639
/*
@@ -695,7 +695,7 @@ RestoreRelationMap(char *startAddress)
695695
* Note that the local case requires DatabasePath to be set up.
696696
*/
697697
static void
698-
load_relmap_file(bool shared)
698+
load_relmap_file(bool shared, bool lock_held)
699699
{
700700
RelMapFile *map;
701701
char mapfilename[MAXPGPATH];
@@ -725,12 +725,15 @@ load_relmap_file(bool shared)
725725
mapfilename)));
726726

727727
/*
728-
* Note: we could take RelationMappingLock in shared mode here, but it
729-
* seems unnecessary since our read() should be atomic against any
730-
* concurrent updater's write(). If the file is updated shortly after we
731-
* look, the sinval signaling mechanism will make us re-read it before we
732-
* are able to access any relation that's affected by the change.
728+
* Grab the lock to prevent the file from being updated while we read it,
729+
* unless the caller is already holding the lock. If the file is updated
730+
* shortly after we look, the sinval signaling mechanism will make us
731+
* re-read it before we are able to access any relation that's affected by
732+
* the change.
733733
*/
734+
if (!lock_held)
735+
LWLockAcquire(RelationMappingLock, LW_SHARED);
736+
734737
pgstat_report_wait_start(WAIT_EVENT_RELATION_MAP_READ);
735738
r = read(fd, map, sizeof(RelMapFile));
736739
if (r != sizeof(RelMapFile))
@@ -747,6 +750,9 @@ load_relmap_file(bool shared)
747750
}
748751
pgstat_report_wait_end();
749752

753+
if (!lock_held)
754+
LWLockRelease(RelationMappingLock);
755+
750756
if (CloseTransientFile(fd) != 0)
751757
ereport(FATAL,
752758
(errcode_for_file_access(),
@@ -969,7 +975,7 @@ perform_relmap_update(bool shared, const RelMapFile *updates)
969975
LWLockAcquire(RelationMappingLock, LW_EXCLUSIVE);
970976

971977
/* Be certain we see any other updates just made */
972-
load_relmap_file(shared);
978+
load_relmap_file(shared, true);
973979

974980
/* Prepare updated data in a local variable */
975981
if (shared)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy