Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+20-14
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)