agora inbox for [email protected]help / color / mirror / Atom feed
[PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. 267+ messages / 2 participants [nested] [flat]
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. @ 2024-05-18 01:41 Thomas Munro <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw) When backend processes were launched in EXEC_BACKEND builds, they would run LocalProcessControlFile() to read in pg_control and extract several important settings. This happens too early to acquire ControlFileLock, and the postmaster is also not allowed to acquire ControlFileLock, so it can't safely take a copy to give to the child. Instead, pass down the "proto-controlfile" that was read by the postmaster in LocalProcessControlFile(). Introduce functions ExportProtoControlFile() and ImportProtoControlFile() to allow that. Subprocesses will extract information from that, and then later attach to the current control file in shared memory. Reported-by: Melanie Plageman <[email protected]> per Windows CI failure Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com --- src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++-- src/backend/postmaster/launch_backend.c | 21 +++++++---- src/include/access/xlog.h | 5 +++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 13ec6225b85..e52517eb9c1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL; */ static ControlFileData *ControlFile = NULL; +#ifdef EXEC_BACKEND +static ControlFileData *ProtoControlFile = NULL; +#endif + /* * Calculate the amount of space left on the page after 'endptr'. Beware * multiple evaluation! @@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void); static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version); static void WriteControlFile(void); static void ReadControlFile(void); +static void ScanControlFile(void); static void UpdateControlFile(void); static char *str_time(pg_time_t tnow, char *buf, size_t bufsize); @@ -4385,9 +4390,7 @@ WriteControlFile(void) static void ReadControlFile(void) { - pg_crc32c crc; int fd; - char wal_segsz_str[20]; int r; /* @@ -4420,6 +4423,15 @@ ReadControlFile(void) close(fd); + ScanControlFile(); +} + +static void +ScanControlFile(void) +{ + static char wal_segsz_str[20]; + pg_crc32c crc; + /* * Check for expected pg_control format version. If this is wrong, the * CRC check will likely fail because we'll be checking the wrong number @@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset) Assert(reset || ControlFile == NULL); ControlFile = palloc_object(ControlFileData); ReadControlFile(); + +#ifdef EXEC_BACKEND + /* We need to be able to give this to subprocesses. */ + ProtoControlFile = ControlFile; +#endif } +#ifdef EXEC_BACKEND +void +ExportProtoControlFile(ControlFileData *copy) +{ + *copy = *ProtoControlFile; +} + +/* + * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's + * startup. This receives the same file that the postmaster first read. + */ +void +ImportProtoControlFile(const ControlFileData *copy) +{ + ControlFile = palloc(sizeof(ControlFileData)); + *ControlFile = *copy; + ScanControlFile(); +} +#endif + /* * Get the wal_level from the control file. For a standby, this value should be * considered as its active wal_level, because it may be different from what @@ -5061,7 +5098,12 @@ XLOGShmemInit(void) if (localControlFile) { memcpy(ControlFile, localControlFile, sizeof(ControlFileData)); +#ifdef EXEC_BACKEND + /* We still hold a reference to give to subprocesses. */ + Assert(ProtoControlFile == localControlFile); +#else pfree(localControlFile); +#endif } /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 45690b11c99..e08a405f949 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -33,6 +33,9 @@ #include <unistd.h> +#include "access/xlog.h" +#include "catalog/pg_control.h" +#include "common/file_utils.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "postmaster/autovacuum.h" @@ -133,6 +136,14 @@ typedef struct int MyPMChildSlot; + /* + * A copy of the ControlFileData from early in Postmaster startup. We + * need to access its contents it at a phase of initialization before we + * are allowed to acquire LWLocks, so we can't just use shared memory or + * read the file from disk. + */ + ControlFileData proto_controlfile; + /* * These are only used by backend processes, but are here because passing * a socket needs some special handling on Windows. 'client_sock' is an @@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[]) */ checkDataDir(); - /* - * (re-)read control file, as it contains config. The postmaster will - * already have read this, but this process doesn't know about that. - */ - LocalProcessControlFile(false); - /* * Reload any libraries that were preloaded by the postmaster. Since we * exec'd this process, those libraries didn't come along with us; but we @@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param, param->MaxBackends = MaxBackends; param->num_pmchild_slots = num_pmchild_slots; + ExportProtoControlFile(¶m->proto_controlfile); + #ifdef WIN32 param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, @@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param) strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); + ImportProtoControlFile(¶m->proto_controlfile); + /* * We need to restore fd.c's counts of externally-opened FDs; to avoid * confusion, be sure to do this after restoring max_safe_fds. (Note: diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index fdfb572467b..f1f3ad4e96e 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -208,6 +208,7 @@ typedef enum WALAvailability struct XLogRecData; struct XLogReaderState; +struct ControlFileData; extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, XLogRecPtr fpw_lsn, @@ -250,6 +251,10 @@ extern void XLOGShmemInit(void); extern void BootStrapXLOG(uint32 data_checksum_version); extern void InitializeWalConsistencyChecking(void); extern void LocalProcessControlFile(bool reset); +#ifdef EXEC_BACKEND +extern void ExportProtoControlFile(struct ControlFileData *copy); +extern void ImportProtoControlFile(const struct ControlFileData *copy); +#endif extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); -- 2.47.3 --dhbc6bswyy6qufwn-- ^ permalink raw reply [nested|flat] 267+ messages in thread
* [PATCH v1 2/2] Try to avoid a rewrite when adding a stored generated column @ 2026-03-16 23:28 Alberto Piai <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Alberto Piai @ 2026-03-16 23:28 UTC (permalink / raw) This builds upon basic support for ... ALTER COLUMN ... ADD GENERATED ALWAYS AS (expr) STORED If we can find a constraint which proves that the given column is already always equal to the new generated column expression, skip the expensive rewrite of the table. The check constraint must use an equality operator which is mergejoinable, and the expression must match exactly the generated column's default expression. --- src/backend/catalog/pg_constraint.c | 75 +++++++++++ src/backend/commands/tablecmds.c | 46 ++++--- src/include/catalog/pg_constraint.h | 2 + src/test/regress/expected/alter_table.out | 155 +++++++++++++++++++++- src/test/regress/sql/alter_table.sql | 81 +++++++++++ 5 files changed, 339 insertions(+), 20 deletions(-) diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index b12765ae691..8f207c4a79d 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -17,6 +17,7 @@ #include "access/genam.h" #include "access/gist.h" #include "access/htup_details.h" +#include "access/relation.h" #include "access/sysattr.h" #include "access/table.h" #include "catalog/catalog.h" @@ -29,6 +30,8 @@ #include "catalog/pg_type.h" #include "commands/defrem.h" #include "common/int.h" +#include "nodes/nodeFuncs.h" +#include "parser/parse_relation.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/fmgroids.h" @@ -694,6 +697,78 @@ findDomainNotNullConstraint(Oid typid) return retval; } +/* + * Given a relation, an attnum and a (cooked) expression, this returns true if + * it finds a CHECK constraint which proves that the given column is equal to + * the expression. + * + * The constraint must use a mergejoinable operator for the type of the column, + * a concept used by the planner as well to infer equivalence classes on the + * terms in a query (see op_mergejoinable()). + * + * The expressions are compared structurally, so they must match exactly for + * this check to succeed. + */ +bool +findStructuralCheckConstraintOnAttr(Oid relid, AttrNumber attnum, + const Node *target_expr) +{ + Relation pg_constraint; + HeapTuple conTup; + SysScanDesc scan; + ScanKeyData key; + bool found = false; + + pg_constraint = table_open(ConstraintRelationId, AccessShareLock); + ScanKeyInit(&key, + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, + true, NULL, 1, &key); + + while (HeapTupleIsValid(conTup = systable_getnext(scan))) + { + Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(conTup); + char *conbin; + Datum val; + Node *conexpr; + + if (con->contype != CONSTRAINT_CHECK) + continue; + if (!con->convalidated) + continue; + + val = SysCacheGetAttrNotNull(CONSTROID, conTup, + Anum_pg_constraint_conbin); + conbin = TextDatumGetCString(val); + conexpr = stringToNode(conbin); + + if (IsA(conexpr, OpExpr)) + { + OpExpr *op = (OpExpr *) conexpr; + + if (list_length(op->args) == 2 && IsA(linitial(op->args), Var)) + { + Var *var = (Var *) linitial(op->args); + + if (var->varattno == attnum && + op_mergejoinable(op->opno, exprType((Node *) var)) && + equal(lsecond(op->args), target_expr)) + { + found = true; + break; + } + } + } + } + + systable_endscan(scan); + table_close(pg_constraint, AccessShareLock); + + return found; +} + /* * Given a pg_constraint tuple for a not-null constraint, return the column * number it is for. diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index e7386e81b07..005fbf78fbf 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8863,6 +8863,7 @@ ATExecAddGeneratedAsExprStored(AlteredTableInfo *tab, NewColumnValue *newval; RawColumnDefault *rawEnt; Relation pg_attribute; + bool rewrite; Assert(def->raw_expr != NULL); Assert(def->cooked_expr == NULL); @@ -8926,29 +8927,36 @@ ATExecAddGeneratedAsExprStored(AlteredTableInfo *tab, /* Make above changes visible */ CommandCounterIncrement(); - /* - * Clear all the missing values if we're rewriting the table, since this - * renders them pointless. - */ - RelationClearMissing(rel); - - /* Make above changes visible */ - CommandCounterIncrement(); - - /* Drop any pg_statistic entry for the column */ - RemoveStatistics(RelationGetRelid(rel), attnum); - /* Build a concrete expression for the new default (generated) value */ defval = (Expr *) build_column_default(rel, attnum); defval = expression_planner(defval); - /* Schedule a rewrite */ - newval = palloc0_object(NewColumnValue); - newval->attnum = attnum; - newval->expr = defval; - newval->is_generated = true; - tab->newvals = lappend(tab->newvals, newval); - tab->rewrite |= AT_REWRITE_DEFAULT_VAL; + rewrite = !findStructuralCheckConstraintOnAttr(RelationGetRelid(rel), + attnum, + (Node *) defval); + + if (rewrite) + { + /* + * Clear all the missing values if we're rewriting the table, since + * this renders them pointless. + */ + RelationClearMissing(rel); + + /* Make above changes visible */ + CommandCounterIncrement(); + + /* Drop any pg_statistic entry for the column */ + RemoveStatistics(RelationGetRelid(rel), attnum); + + /* Schedule a rewrite */ + newval = palloc0_object(NewColumnValue); + newval->attnum = attnum; + newval->expr = defval; + newval->is_generated = true; + tab->newvals = lappend(tab->newvals, newval); + tab->rewrite |= AT_REWRITE_DEFAULT_VAL; + } InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), attnum); diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h index 1b7fedf1750..7ac9e00c28b 100644 --- a/src/include/catalog/pg_constraint.h +++ b/src/include/catalog/pg_constraint.h @@ -266,6 +266,8 @@ extern char *ChooseConstraintName(const char *name1, const char *name2, extern HeapTuple findNotNullConstraintAttnum(Oid relid, AttrNumber attnum); extern HeapTuple findNotNullConstraint(Oid relid, const char *colname); extern HeapTuple findDomainNotNullConstraint(Oid typid); +extern bool findStructuralCheckConstraintOnAttr(Oid relid, AttrNumber attnum, + const Node *target_expr); extern AttrNumber extractNotNullColumn(HeapTuple constrTup); extern bool AdjustNotNullInheritance(Oid relid, AttrNumber attnum, const char *new_conname, bool is_local, bool is_no_inherit, bool is_notvalid); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 75f64628aef..4062f985c5a 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -4943,6 +4943,157 @@ select :idx_filenode_before != :idx_filenode_after as did_rewrite_idx; t (1 row) +-- turning a regular column into a stored generated column +-- without rewriting the table (when a check constraint proves it isn't needed) +create table testgen.t4 (a int, b int not null); +insert into testgen.t4 (a, b) select x, x * 2 from generate_series(0, 5) x; +alter table testgen.t4 add constraint chk_gen_clause check (b = a * 2); +select pg_relation_filenode('testgen.t4') as t4_filenode_before \gset +alter table testgen.t4 alter column b add generated always as (a * 2) stored; +select pg_relation_filenode('testgen.t4') as t4_filenode_after \gset +select :t4_filenode_before = :t4_filenode_after as did_skip_rewrite; + did_skip_rewrite +------------------ + t +(1 row) + +\d+ testgen.t4 + Table "testgen.t4" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+------------------------------------+---------+--------------+------------- + a | integer | | | | plain | | + b | integer | | not null | generated always as (a * 2) stored | plain | | +Check constraints: + "chk_gen_clause" CHECK (b = (a * 2)) +Not-null constraints: + "t4_b_not_null" NOT NULL "b" + +drop table testgen.t4; +-- turning a regular column into a stored generated column +-- same as the previous case, but a rewrite happens since the constraint is not +-- valid +create table testgen.t4 (a int, b int not null); +insert into testgen.t4 (a, b) select x, x * 2 from generate_series(0, 5) x; +alter table testgen.t4 add constraint chk_gen_clause check (b = a * 2) not valid; +select pg_relation_filenode('testgen.t4') as t4_filenode_before \gset +alter table testgen.t4 alter column b add generated always as (a * 2) stored; +select pg_relation_filenode('testgen.t4') as t4_filenode_after \gset +select :t4_filenode_before != :t4_filenode_after as did_rewrite; + did_rewrite +------------- + t +(1 row) + +\d+ testgen.t4 + Table "testgen.t4" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+------------------------------------+---------+--------------+------------- + a | integer | | | | plain | | + b | integer | | not null | generated always as (a * 2) stored | plain | | +Check constraints: + "chk_gen_clause" CHECK (b = (a * 2)) NOT VALID +Not-null constraints: + "t4_b_not_null" NOT NULL "b" + +drop table testgen.t4; +-- turning a regular column into a stored generated column +-- same as the previous case, but a rewrite happens since the constraint +-- operator is not mergejoinable +create table testgen.t4 (a int, b int not null); +insert into testgen.t4 (a, b) select x, x * 2 from generate_series(0, 5) x; +alter table testgen.t4 add constraint chk_gen_clause check (b >= a * 2); +select pg_relation_filenode('testgen.t4') as t4_filenode_before \gset +alter table testgen.t4 alter column b add generated always as (a * 3) stored; +select pg_relation_filenode('testgen.t4') as t4_filenode_after \gset +select :t4_filenode_before != :t4_filenode_after as did_rewrite; + did_rewrite +------------- + t +(1 row) + +\d+ testgen.t4 + Table "testgen.t4" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+------------------------------------+---------+--------------+------------- + a | integer | | | | plain | | + b | integer | | not null | generated always as (a * 3) stored | plain | | +Check constraints: + "chk_gen_clause" CHECK (b >= (a * 2)) +Not-null constraints: + "t4_b_not_null" NOT NULL "b" + +drop table testgen.t4; +-- test the whole process for adding a stored generated column without +-- long-lived exclusive locks +create table testgen.t5 (a int); +select pg_relation_filenode('testgen.t5') as t5_filenode_before \gset +insert into testgen.t5 select x from generate_series(1, 5) x; +alter table testgen.t5 add column b int; +-- take care of new and updated columns +create function testgen.gen () returns trigger language plpgsql as $$ +begin + new.b = new.a * 2; return new; +end +$$; +create trigger testgen_gen + before insert or update on testgen.t5 + for each row execute function testgen.gen(); +-- add the constraint as not valid: enforced only for new and updated rows +begin; +alter table testgen.t5 + add constraint chk_gen_clause check (b = a * 2) not valid; +select locktype, mode from pg_locks + where relation = 'testgen.t5'::regclass and granted; + locktype | mode +----------+--------------------- + relation | AccessExclusiveLock +(1 row) + +commit; +insert into testgen.t5 (a) values (100), (200), (300); +-- backfill existing rows at the appropriate pace +update testgen.t5 set b = a * 2 where b is null; +-- validate: this scans the table, but without an exclusive lock +begin; +alter table testgen.t5 validate constraint chk_gen_clause; +select locktype, mode from pg_locks + where relation = 'testgen.t5'::regclass and granted; + locktype | mode +----------+-------------------------- + relation | ShareUpdateExclusiveLock +(1 row) + +commit; +-- now the schema update, which skips the rewrite because of the check +begin; +drop trigger testgen_gen on testgen.t5; +alter table testgen.t5 alter column b + add generated always as (a * 2) stored; +select locktype, mode from pg_locks +where relation = 'testgen.t5'::regclass and granted; + locktype | mode +----------+--------------------- + relation | AccessShareLock + relation | AccessExclusiveLock +(2 rows) + +commit; +select pg_relation_filenode('testgen.t5') as t5_filenode_after \gset +select :t5_filenode_before = :t5_filenode_after as did_skip_rewrite; + did_skip_rewrite +------------------ + t +(1 row) + +\d+ testgen.t5 + Table "testgen.t5" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+------------------------------------+---------+--------------+------------- + a | integer | | | | plain | | + b | integer | | | generated always as (a * 2) stored | plain | | +Check constraints: + "chk_gen_clause" CHECK (b = (a * 2)) + -- tests for invalid invocations alter table doesnotexist alter column foo add generated always as (bar * 2) stored; @@ -4980,8 +5131,10 @@ alter table testgen.tpart alter column b add generated always as (a * 2) stored; ERROR: ALTER action ALTER COLUMN ... ADD GENERATED ALWAYS AS (...) STORED cannot be performed on relation "tpart" DETAIL: This operation is not supported for partitioned tables. drop schema testgen cascade; -NOTICE: drop cascades to 4 other objects +NOTICE: drop cascades to 6 other objects DETAIL: drop cascades to table testgen.t3 +drop cascades to table testgen.t5 +drop cascades to function testgen.gen() drop cascades to table testgen.t1 drop cascades to table testgen.t2 drop cascades to table testgen.tpart diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index d776595a6ed..821f04e8073 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -3197,6 +3197,87 @@ alter table testgen.t3 alter column b add generated always as (a * 2) stored; select pg_relation_filenode('testgen.idx_b') as idx_filenode_after \gset select :idx_filenode_before != :idx_filenode_after as did_rewrite_idx; +-- turning a regular column into a stored generated column +-- without rewriting the table (when a check constraint proves it isn't needed) +create table testgen.t4 (a int, b int not null); +insert into testgen.t4 (a, b) select x, x * 2 from generate_series(0, 5) x; +alter table testgen.t4 add constraint chk_gen_clause check (b = a * 2); +select pg_relation_filenode('testgen.t4') as t4_filenode_before \gset +alter table testgen.t4 alter column b add generated always as (a * 2) stored; +select pg_relation_filenode('testgen.t4') as t4_filenode_after \gset +select :t4_filenode_before = :t4_filenode_after as did_skip_rewrite; +\d+ testgen.t4 +drop table testgen.t4; + +-- turning a regular column into a stored generated column +-- same as the previous case, but a rewrite happens since the constraint is not +-- valid +create table testgen.t4 (a int, b int not null); +insert into testgen.t4 (a, b) select x, x * 2 from generate_series(0, 5) x; +alter table testgen.t4 add constraint chk_gen_clause check (b = a * 2) not valid; +select pg_relation_filenode('testgen.t4') as t4_filenode_before \gset +alter table testgen.t4 alter column b add generated always as (a * 2) stored; +select pg_relation_filenode('testgen.t4') as t4_filenode_after \gset +select :t4_filenode_before != :t4_filenode_after as did_rewrite; +\d+ testgen.t4 +drop table testgen.t4; + +-- turning a regular column into a stored generated column +-- same as the previous case, but a rewrite happens since the constraint +-- operator is not mergejoinable +create table testgen.t4 (a int, b int not null); +insert into testgen.t4 (a, b) select x, x * 2 from generate_series(0, 5) x; +alter table testgen.t4 add constraint chk_gen_clause check (b >= a * 2); +select pg_relation_filenode('testgen.t4') as t4_filenode_before \gset +alter table testgen.t4 alter column b add generated always as (a * 3) stored; +select pg_relation_filenode('testgen.t4') as t4_filenode_after \gset +select :t4_filenode_before != :t4_filenode_after as did_rewrite; +\d+ testgen.t4 +drop table testgen.t4; + +-- test the whole process for adding a stored generated column without +-- long-lived exclusive locks +create table testgen.t5 (a int); +select pg_relation_filenode('testgen.t5') as t5_filenode_before \gset +insert into testgen.t5 select x from generate_series(1, 5) x; +alter table testgen.t5 add column b int; +-- take care of new and updated columns +create function testgen.gen () returns trigger language plpgsql as $$ +begin + new.b = new.a * 2; return new; +end +$$; +create trigger testgen_gen + before insert or update on testgen.t5 + for each row execute function testgen.gen(); +-- add the constraint as not valid: enforced only for new and updated rows +begin; +alter table testgen.t5 + add constraint chk_gen_clause check (b = a * 2) not valid; +select locktype, mode from pg_locks + where relation = 'testgen.t5'::regclass and granted; +commit; +insert into testgen.t5 (a) values (100), (200), (300); +-- backfill existing rows at the appropriate pace +update testgen.t5 set b = a * 2 where b is null; +-- validate: this scans the table, but without an exclusive lock +begin; +alter table testgen.t5 validate constraint chk_gen_clause; +select locktype, mode from pg_locks + where relation = 'testgen.t5'::regclass and granted; +commit; +-- now the schema update, which skips the rewrite because of the check +begin; +drop trigger testgen_gen on testgen.t5; +alter table testgen.t5 alter column b + add generated always as (a * 2) stored; +select locktype, mode from pg_locks +where relation = 'testgen.t5'::regclass and granted; +commit; +select pg_relation_filenode('testgen.t5') as t5_filenode_after \gset +select :t5_filenode_before = :t5_filenode_after as did_skip_rewrite; +\d+ testgen.t5 + -- tests for invalid invocations alter table doesnotexist alter column foo add generated always as (bar * 2) stored; -- 2.51.2 --24dzbv6kpqxe4yje-- ^ permalink raw reply [nested|flat] 267+ messages in thread
end of thread, other threads:[~2026-03-16 23:28 UTC | newest] Thread overview: 267+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]> 2026-03-16 23:28 [PATCH v1 2/2] Try to avoid a rewrite when adding a stored generated column Alberto Piai <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox