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 v5] Track skipped vacuum and analyze activity per relation @ 2026-03-24 04:09 Yugo Nagata <[email protected]> 0 siblings, 0 replies; 267+ messages in thread From: Yugo Nagata @ 2026-03-24 04:09 UTC (permalink / raw) This commit adds eight fields to the relation statistics that track the last time vacuum or analyze has been attempted but skipped due to lock unavailability, along with their counts: - last_skipped_vacuum - last_skipped_autovacuum - last_skipped_analyze - last_skipped_autoanalyze - skipped_vacuum_count - skipped_autovacuum_count - skipped_analyze_count - skipped_autoanalyze_count These field can help users confirm that autovacuum is actively attempting to run on a table that has not been vacuumed or analyzed for a long time, and that the lack of progress is due to repeated skips rather than inactivity. --- doc/src/sgml/monitoring.sgml | 88 ++++++ src/backend/catalog/system_views.sql | 8 + src/backend/commands/vacuum.c | 100 +++++-- src/backend/utils/activity/pgstat_relation.c | 64 +++++ src/backend/utils/adt/pgstatfuncs.c | 24 ++ src/include/catalog/pg_proc.dat | 32 +++ src/include/pgstat.h | 16 ++ .../isolation/expected/vacuum-skip-locked.out | 260 ++++++++++++++++-- .../isolation/specs/vacuum-skip-locked.spec | 41 +-- src/test/regress/expected/rules.out | 24 ++ 10 files changed, 601 insertions(+), 56 deletions(-) diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 08d5b824552..a9b579d87a9 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -4387,6 +4387,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage </para></entry> </row> + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>last_skipped_vacuum</structfield> <type>timestamp with time zone</type> + </para> + <para> + Last time a manual vacuum on this table was attempted but skipped due to + lock unavailability (not counting <command>VACUUM FULL</command>) + </para></entry> + </row> + <row> <entry role="catalog_table_entry"><para role="column_definition"> <structfield>last_autovacuum</structfield> <type>timestamp with time zone</type> @@ -4397,6 +4407,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage </para></entry> </row> + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>last_skipped_autovacuum</structfield> <type>timestamp with time zone</type> + </para> + <para> + Last time a vacuum on this table by the autovacuum daemon was attempted + but skipped due to lock unavailability + </para></entry> + </row> + <row> <entry role="catalog_table_entry"><para role="column_definition"> <structfield>last_analyze</structfield> <type>timestamp with time zone</type> @@ -4406,6 +4426,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage </para></entry> </row> + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>last_skipped_analyze</structfield> <type>timestamp with time zone</type> + </para> + <para> + Last time a manual analyze on this table was attempted but skipped due to + lock unavailability + </para></entry> + </row> + <row> <entry role="catalog_table_entry"><para role="column_definition"> <structfield>last_autoanalyze</structfield> <type>timestamp with time zone</type> @@ -4416,6 +4446,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage </para></entry> </row> + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>last_skipped_autoanalyze</structfield> <type>timestamp with time zone</type> + </para> + <para> + Last time at which an analyze on this table by the autovacuum was + attempted but skipped due to lock unavailability + </para></entry> + </row> + <row> <entry role="catalog_table_entry"><para role="column_definition"> <structfield>vacuum_count</structfield> <type>bigint</type> @@ -4426,6 +4466,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage </para></entry> </row> + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>skipped_vacuum_count</structfield> <type>bigint</type> + </para> + <para> + Number of times manual vacuums on this table have been attempted but skipped + due to lock unavailability (not counting <command>VACUUM FULL</command>) + </para></entry> + </row> + <row> <entry role="catalog_table_entry"><para role="column_definition"> <structfield>autovacuum_count</structfield> <type>bigint</type> @@ -4436,6 +4486,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage </para></entry> </row> + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>skipped_autovacuum_count</structfield> <type>bigint</type> + </para> + <para> + Number of times vacuums on this table by the autovacuum daemon have been + attempted but skipped due to lock unavailability + </para></entry> + </row> + <row> <entry role="catalog_table_entry"><para role="column_definition"> <structfield>analyze_count</structfield> <type>bigint</type> @@ -4445,6 +4505,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage </para></entry> </row> + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>skipped_analyze_count</structfield> <type>bigint</type> + </para> + <para> + Number of times manual analyzes on this table have been attempted but + skipped due to lock unavailability + </para></entry> + </row> + <row> <entry role="catalog_table_entry"><para role="column_definition"> <structfield>autoanalyze_count</structfield> <type>bigint</type> @@ -4455,6 +4525,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage </para></entry> </row> + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>skipped_autoanalyze_count</structfield> <type>bigint</type> + </para> + <para> + Number of times analyzes on this table by the autovacuum daemon have + been attempted but skipped due to lock unavailability + </para></entry> + </row> + <row> <entry role="catalog_table_entry"><para role="column_definition"> <structfield>total_vacuum_time</structfield> <type>double precision</type> @@ -4510,6 +4590,14 @@ description | Waiting for a newly initialized WAL file to reach durable storage </tgroup> </table> + <note> + <para> + When a manual vacuum or analyze on a parent table in an inheritance or + partitioning hierarchy is skipped, the statistics are recorded only for + the parent table, not for its children. + </para> + </note> + </sect2> <sect2 id="monitoring-pg-stat-autovacuum-scores-view"> diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 73a1c1c4670..f509fc7876b 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -736,13 +736,21 @@ CREATE VIEW pg_stat_all_tables AS pg_stat_get_mod_since_analyze(C.oid) AS n_mod_since_analyze, pg_stat_get_ins_since_vacuum(C.oid) AS n_ins_since_vacuum, pg_stat_get_last_vacuum_time(C.oid) as last_vacuum, + pg_stat_get_last_skipped_vacuum_time(C.oid) as last_skipped_vacuum, pg_stat_get_last_autovacuum_time(C.oid) as last_autovacuum, + pg_stat_get_last_skipped_autovacuum_time(C.oid) as last_skipped_autovacuum, pg_stat_get_last_analyze_time(C.oid) as last_analyze, + pg_stat_get_last_skipped_analyze_time(C.oid) as last_skipped_analyze, pg_stat_get_last_autoanalyze_time(C.oid) as last_autoanalyze, + pg_stat_get_last_skipped_autoanalyze_time(C.oid) as last_skipped_autoanalyze, pg_stat_get_vacuum_count(C.oid) AS vacuum_count, + pg_stat_get_skipped_vacuum_count(C.oid) AS skipped_vacuum_count, pg_stat_get_autovacuum_count(C.oid) AS autovacuum_count, + pg_stat_get_skipped_autovacuum_count(C.oid) AS skipped_autovacuum_count, pg_stat_get_analyze_count(C.oid) AS analyze_count, + pg_stat_get_skipped_analyze_count(C.oid) AS skipped_analyze_count, pg_stat_get_autoanalyze_count(C.oid) AS autoanalyze_count, + pg_stat_get_skipped_autoanalyze_count(C.oid) AS skipped_autoanalyze_count, pg_stat_get_total_vacuum_time(C.oid) AS total_vacuum_time, pg_stat_get_total_autovacuum_time(C.oid) AS total_autovacuum_time, pg_stat_get_total_analyze_time(C.oid) AS total_analyze_time, diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 99d0db82ed7..df6526225e4 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -793,8 +793,25 @@ vacuum_open_relation(Oid relid, RangeVar *relation, uint32 options, rel = try_relation_open(relid, NoLock); else { + int flags = 0; rel = NULL; rel_lock = false; + + if ((options & VACOPT_VACUUM) != 0 && (options & VACOPT_FULL) == 0) + { + if (AmAutoVacuumWorkerProcess()) + flags |= PGSTAT_REPORT_SKIPPED_AUTOVACUUM; + else + flags |= PGSTAT_REPORT_SKIPPED_VACUUM; + } + if ((options & VACOPT_ANALYZE) != 0) + { + if (AmAutoVacuumWorkerProcess()) + flags |= PGSTAT_REPORT_SKIPPED_AUTOANALYZE; + else + flags |= PGSTAT_REPORT_SKIPPED_ANALYZE; + } + pgstat_report_skipped_vacuum_analyze(relid, flags); } /* if relation is opened, leave */ @@ -905,7 +922,6 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context, Form_pg_class classForm; bool include_children; bool is_partitioned_table; - int rvr_opts; /* * Since autovacuum workers supply OIDs when calling vacuum(), no @@ -918,29 +934,69 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context, * below, as well as find_all_inheritors's expectation that the caller * holds some lock on the starting relation. */ - rvr_opts = (options & VACOPT_SKIP_LOCKED) ? RVR_SKIP_LOCKED : 0; - relid = RangeVarGetRelidExtended(vrel->relation, - AccessShareLock, - rvr_opts, - NULL, NULL); - - /* - * If the lock is unavailable, emit the same log statement that - * vacuum_rel() and analyze_rel() would. - */ - if (!OidIsValid(relid)) + if (!(options & VACOPT_SKIP_LOCKED)) { - if (options & VACOPT_VACUUM) - ereport(WARNING, - (errcode(ERRCODE_LOCK_NOT_AVAILABLE), - errmsg("skipping vacuum of \"%s\" --- lock not available", - vrel->relation->relname))); - else - ereport(WARNING, - (errcode(ERRCODE_LOCK_NOT_AVAILABLE), - errmsg("skipping analyze of \"%s\" --- lock not available", + relid = RangeVarGetRelidExtended(vrel->relation, + AccessShareLock, + 0, NULL, NULL); + if (!OidIsValid(relid)) + return vacrels; + } + else + { + /* Get relid for reporting before taking a lock */ + relid = RangeVarGetRelid(vrel->relation, NoLock, false); + + if (!ConditionalLockRelationOid(relid, AccessShareLock)) + { + int flags = 0; + /* + * If the lock is unavailable, emit the same log statement that + * vacuum_rel() and analyze_rel() would. + */ + if (options & VACOPT_VACUUM) + ereport(WARNING, + (errcode(ERRCODE_LOCK_NOT_AVAILABLE), + errmsg("skipping vacuum of \"%s\" --- lock not available", vrel->relation->relname))); - return vacrels; + else + ereport(WARNING, + (errcode(ERRCODE_LOCK_NOT_AVAILABLE), + errmsg("skipping analyze of \"%s\" --- lock not available", + vrel->relation->relname))); + + if ((options & VACOPT_VACUUM) != 0 && (options & VACOPT_FULL) == 0) + flags |= PGSTAT_REPORT_SKIPPED_VACUUM; + if ((options & VACOPT_ANALYZE) != 0) + flags |= PGSTAT_REPORT_SKIPPED_ANALYZE; + + pgstat_report_skipped_vacuum_analyze(relid, flags); + + return vacrels; + } + + /* + * Now that we have the lock, probe to see if the relation really + * exists or not. + */ + if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relid))) + { + if (options & VACOPT_VACUUM) + ereport(WARNING, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("skipping vacuum of \"%s\" --- relation no longer exists", + vrel->relation->relname))); + else + ereport(WARNING, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("skipping analyze of \"%s\" --- relation no longer exists", + vrel->relation->relname))); + + /* Release useless lock */ + UnlockRelationOid(relid, AccessShareLock); + + return vacrels; + } } /* diff --git a/src/backend/utils/activity/pgstat_relation.c b/src/backend/utils/activity/pgstat_relation.c index b2ca28f83ba..532d9023f8c 100644 --- a/src/backend/utils/activity/pgstat_relation.c +++ b/src/backend/utils/activity/pgstat_relation.c @@ -17,12 +17,14 @@ #include "postgres.h" +#include "access/htup_details.h" #include "access/twophase_rmgr.h" #include "access/xact.h" #include "catalog/catalog.h" #include "utils/memutils.h" #include "utils/pgstat_internal.h" #include "utils/rel.h" +#include "utils/syscache.h" #include "utils/timestamp.h" @@ -367,6 +369,68 @@ pgstat_report_analyze(Relation rel, (void) pgstat_flush_backend(false, PGSTAT_BACKEND_FLUSH_IO); } +/* + * Report that the table was skipped during vacuum or/and analyze. + */ +void +pgstat_report_skipped_vacuum_analyze(Oid relid, int flags) +{ + PgStat_EntryRef *entry_ref; + PgStatShared_Relation *shtabentry; + PgStat_StatTabEntry *tabentry; + TimestampTz ts; + HeapTuple classTup; + bool isshared; + + if (!pgstat_track_counts || !flags) + return; + + classTup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(classTup)) + return; /* somebody deleted the rel, forget it */ + isshared = ((Form_pg_class) GETSTRUCT(classTup))->relisshared; + ReleaseSysCache(classTup); + + /* Store the data in the table's hash table entry. */ + ts = GetCurrentTimestamp(); + + /* block acquiring lock for the same reason as pgstat_report_autovac() */ + entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION, + isshared ? InvalidOid : MyDatabaseId, + relid, false); + + shtabentry = (PgStatShared_Relation *) entry_ref->shared_stats; + tabentry = &shtabentry->stats; + + if (flags & PGSTAT_REPORT_SKIPPED_VACUUM) + { + tabentry->last_skipped_vacuum_time = ts; + tabentry->skipped_vacuum_count++; + } + else if (flags & PGSTAT_REPORT_SKIPPED_AUTOVACUUM) + { + tabentry->last_skipped_autovacuum_time = ts; + tabentry->skipped_autovacuum_count++; + } + + if (flags & PGSTAT_REPORT_SKIPPED_ANALYZE) + { + tabentry->last_skipped_analyze_time = ts; + tabentry->skipped_analyze_count++; + } + else if (flags & PGSTAT_REPORT_SKIPPED_AUTOANALYZE) + { + tabentry->last_skipped_autoanalyze_time = ts; + tabentry->skipped_autoanalyze_count++; + } + + pgstat_unlock_entry(entry_ref); + + /* see pgstat_report_vacuum() */ + pgstat_flush_io(false); + (void) pgstat_flush_backend(false, PGSTAT_BACKEND_FLUSH_IO); +} + /* * count a tuple insertion of n tuples */ diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 1408de387ea..90a8968faa0 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -84,6 +84,18 @@ PG_STAT_GET_RELENTRY_INT64(mod_since_analyze) /* pg_stat_get_numscans */ PG_STAT_GET_RELENTRY_INT64(numscans) +/* pg_stat_get_skipped_analyze_count */ +PG_STAT_GET_RELENTRY_INT64(skipped_analyze_count) + +/* pg_stat_get_skipped_autoanalyze_count */ +PG_STAT_GET_RELENTRY_INT64(skipped_autoanalyze_count) + +/* pg_stat_get_skipped_autovacuum_count */ +PG_STAT_GET_RELENTRY_INT64(skipped_autovacuum_count) + +/* pg_stat_get_skipped_vacuum_count */ +PG_STAT_GET_RELENTRY_INT64(skipped_vacuum_count) + /* pg_stat_get_tuples_deleted */ PG_STAT_GET_RELENTRY_INT64(tuples_deleted) @@ -170,6 +182,18 @@ PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_vacuum_time) /* pg_stat_get_lastscan */ PG_STAT_GET_RELENTRY_TIMESTAMPTZ(lastscan) +/* pg_stat_get_last_skipped_analyze_time */ +PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_skipped_analyze_time) + +/* pg_stat_get_last_skipped_autoanalyze_time */ +PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_skipped_autoanalyze_time) + +/* pg_stat_get_last_skipped_autovacuum_time */ +PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_skipped_autovacuum_time) + +/* pg_stat_get_last_skipped_vacuum_time */ +PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_skipped_vacuum_time) + /* pg_stat_get_stat_reset_time */ PG_STAT_GET_RELENTRY_TIMESTAMPTZ(stat_reset_time) diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index fa9ae79082b..32debb34863 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5680,6 +5680,38 @@ proargmodes => '{o,o,o,o,o,o,o,o,o,o}', proargnames => '{oid,score,xid_score,mxid_score,vacuum_score,vacuum_insert_score,analyze_score,do_vacuum,do_analyze,for_wraparound}', prosrc => 'pg_stat_get_autovacuum_scores' }, +{ oid => '8142', descr => 'statistics: last skipped vacuum time for a table', + proname => 'pg_stat_get_last_skipped_vacuum_time', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid', + prosrc => 'pg_stat_get_last_skipped_vacuum_time' }, +{ oid => '8143', descr => 'statistics: last skipped auto vacuum time for a table', + proname => 'pg_stat_get_last_skipped_autovacuum_time', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid', + prosrc => 'pg_stat_get_last_skipped_autovacuum_time' }, +{ oid => '8144', descr => 'statistics: last skipped analyze time for a table', + proname => 'pg_stat_get_last_skipped_analyze_time', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid', + prosrc => 'pg_stat_get_last_skipped_analyze_time' }, +{ oid => '8145', descr => 'statistics: last skipped auto analyze time for a table', + proname => 'pg_stat_get_last_skipped_autoanalyze_time', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid', + prosrc => 'pg_stat_get_last_skipped_autoanalyze_time' }, +{ oid => '8146', descr => 'statistics: number of skipped vacuum for a table', + proname => 'pg_stat_get_skipped_vacuum_count', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_skipped_vacuum_count' }, +{ oid => '8147', descr => 'statistics: number of skipped auto vacuum for a table', + proname => 'pg_stat_get_skipped_autovacuum_count', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_skipped_autovacuum_count' }, +{ oid => '8148', descr => 'statistics: number of skipped analyzes for a table', + proname => 'pg_stat_get_skipped_analyze_count', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_skipped_analyze_count' }, +{ oid => '8149', descr => 'statistics: number of skipped auto analyzes for a table', + proname => 'pg_stat_get_skipped_autoanalyze_count', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_skipped_autoanalyze_count' }, { oid => '1936', descr => 'statistics: currently active backend IDs', proname => 'pg_stat_get_backend_idset', prorows => '100', proretset => 't', provolatile => 's', proparallel => 'r', prorettype => 'int4', diff --git a/src/include/pgstat.h b/src/include/pgstat.h index dfa2e837638..98941f953d1 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -479,6 +479,15 @@ typedef struct PgStat_StatTabEntry TimestampTz last_autoanalyze_time; /* autovacuum initiated */ PgStat_Counter autoanalyze_count; + TimestampTz last_skipped_vacuum_time; /* user initiated vacuum */ + PgStat_Counter skipped_vacuum_count; + TimestampTz last_skipped_autovacuum_time; /* autovacuum initiated */ + PgStat_Counter skipped_autovacuum_count; + TimestampTz last_skipped_analyze_time; /* user initiated */ + PgStat_Counter skipped_analyze_count; + TimestampTz last_skipped_autoanalyze_time; /* autovacuum initiated */ + PgStat_Counter skipped_autoanalyze_count; + PgStat_Counter total_vacuum_time; /* times in milliseconds */ PgStat_Counter total_autovacuum_time; PgStat_Counter total_analyze_time; @@ -703,6 +712,13 @@ extern void pgstat_report_analyze(Relation rel, PgStat_Counter livetuples, PgStat_Counter deadtuples, bool resetcounter, TimestampTz starttime); +/* flags for pgstat_flush_backend() */ +#define PGSTAT_REPORT_SKIPPED_VACUUM (1 << 0) /* vacuum is skipped */ +#define PGSTAT_REPORT_SKIPPED_ANALYZE (1 << 1) /* analyze is skipped */ +#define PGSTAT_REPORT_SKIPPED_AUTOVACUUM (1 << 2) /* autovacuum is skipped */ +#define PGSTAT_REPORT_SKIPPED_AUTOANALYZE (1 << 3) /* autoanalyze is skipped */ +extern void pgstat_report_skipped_vacuum_analyze(Oid relid, int flags); + /* * If stats are enabled, but pending data hasn't been prepared yet, call * pgstat_assoc_relation() to do so. See its comment for why this is done diff --git a/src/test/isolation/expected/vacuum-skip-locked.out b/src/test/isolation/expected/vacuum-skip-locked.out index 99db281a159..e2cff175b7c 100644 --- a/src/test/isolation/expected/vacuum-skip-locked.out +++ b/src/test/isolation/expected/vacuum-skip-locked.out @@ -1,6 +1,6 @@ Parsed test spec with 2 sessions -starting permutation: lock_share vac_specified commit +starting permutation: lock_share vac_specified commit check_stat step lock_share: BEGIN; LOCK part1 IN SHARE MODE; @@ -10,8 +10,22 @@ step vac_specified: VACUUM (SKIP_LOCKED) part1, part2; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); -starting permutation: lock_share vac_all_parts commit +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 0| 0 +part1 | 0| 1| 0| 0 +part2 | 1| 0| 0| 0 +(3 rows) + + +starting permutation: lock_share vac_all_parts commit check_stat step lock_share: BEGIN; LOCK part1 IN SHARE MODE; @@ -20,8 +34,22 @@ step vac_all_parts: VACUUM (SKIP_LOCKED) parted; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); + +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 0| 0 +part1 | 0| 1| 0| 0 +part2 | 1| 0| 0| 0 +(3 rows) + -starting permutation: lock_share analyze_specified commit +starting permutation: lock_share analyze_specified commit check_stat step lock_share: BEGIN; LOCK part1 IN SHARE MODE; @@ -31,8 +59,22 @@ step analyze_specified: ANALYZE (SKIP_LOCKED) part1, part2; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); -starting permutation: lock_share analyze_all_parts commit +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 0| 0 +part1 | 0| 0| 0| 1 +part2 | 0| 0| 1| 0 +(3 rows) + + +starting permutation: lock_share analyze_all_parts commit check_stat step lock_share: BEGIN; LOCK part1 IN SHARE MODE; @@ -41,8 +83,22 @@ step analyze_all_parts: ANALYZE (SKIP_LOCKED) parted; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); + +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 1| 0 +part1 | 0| 0| 0| 1 +part2 | 0| 0| 1| 0 +(3 rows) + -starting permutation: lock_share vac_analyze_specified commit +starting permutation: lock_share vac_analyze_specified commit check_stat step lock_share: BEGIN; LOCK part1 IN SHARE MODE; @@ -52,8 +108,22 @@ step vac_analyze_specified: VACUUM (ANALYZE, SKIP_LOCKED) part1, part2; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); -starting permutation: lock_share vac_analyze_all_parts commit +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 0| 0 +part1 | 0| 1| 0| 1 +part2 | 1| 0| 1| 0 +(3 rows) + + +starting permutation: lock_share vac_analyze_all_parts commit check_stat step lock_share: BEGIN; LOCK part1 IN SHARE MODE; @@ -62,8 +132,22 @@ step vac_analyze_all_parts: VACUUM (ANALYZE, SKIP_LOCKED) parted; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); + +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 1| 0 +part1 | 0| 1| 0| 1 +part2 | 1| 0| 1| 0 +(3 rows) + -starting permutation: lock_share vac_full_specified commit +starting permutation: lock_share vac_full_specified commit check_stat step lock_share: BEGIN; LOCK part1 IN SHARE MODE; @@ -73,8 +157,22 @@ step vac_full_specified: VACUUM (SKIP_LOCKED, FULL) part1, part2; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); -starting permutation: lock_share vac_full_all_parts commit +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 0| 0 +part1 | 0| 0| 0| 0 +part2 | 0| 0| 0| 0 +(3 rows) + + +starting permutation: lock_share vac_full_all_parts commit check_stat step lock_share: BEGIN; LOCK part1 IN SHARE MODE; @@ -83,8 +181,22 @@ step vac_full_all_parts: VACUUM (SKIP_LOCKED, FULL) parted; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); + +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 0| 0 +part1 | 0| 0| 0| 0 +part2 | 0| 0| 0| 0 +(3 rows) -starting permutation: lock_access_exclusive vac_specified commit + +starting permutation: lock_access_exclusive vac_specified commit check_stat step lock_access_exclusive: BEGIN; LOCK part1 IN ACCESS EXCLUSIVE MODE; @@ -94,8 +206,22 @@ step vac_specified: VACUUM (SKIP_LOCKED) part1, part2; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); + +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 0| 0 +part1 | 0| 1| 0| 0 +part2 | 1| 0| 0| 0 +(3 rows) -starting permutation: lock_access_exclusive vac_all_parts commit + +starting permutation: lock_access_exclusive vac_all_parts commit check_stat step lock_access_exclusive: BEGIN; LOCK part1 IN ACCESS EXCLUSIVE MODE; @@ -104,8 +230,22 @@ step vac_all_parts: VACUUM (SKIP_LOCKED) parted; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); + +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 0| 0 +part1 | 0| 1| 0| 0 +part2 | 1| 0| 0| 0 +(3 rows) -starting permutation: lock_access_exclusive analyze_specified commit + +starting permutation: lock_access_exclusive analyze_specified commit check_stat step lock_access_exclusive: BEGIN; LOCK part1 IN ACCESS EXCLUSIVE MODE; @@ -115,8 +255,22 @@ step analyze_specified: ANALYZE (SKIP_LOCKED) part1, part2; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); + +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 0| 0 +part1 | 0| 0| 0| 1 +part2 | 0| 0| 1| 0 +(3 rows) + -starting permutation: lock_access_exclusive analyze_all_parts commit +starting permutation: lock_access_exclusive analyze_all_parts commit check_stat step lock_access_exclusive: BEGIN; LOCK part1 IN ACCESS EXCLUSIVE MODE; @@ -126,8 +280,22 @@ step commit: COMMIT; step analyze_all_parts: <... completed> - -starting permutation: lock_access_exclusive vac_analyze_specified commit +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); + +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 1| 0 +part1 | 0| 0| 1| 0 +part2 | 0| 0| 1| 0 +(3 rows) + + +starting permutation: lock_access_exclusive vac_analyze_specified commit check_stat step lock_access_exclusive: BEGIN; LOCK part1 IN ACCESS EXCLUSIVE MODE; @@ -137,8 +305,22 @@ step vac_analyze_specified: VACUUM (ANALYZE, SKIP_LOCKED) part1, part2; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); + +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 0| 0 +part1 | 0| 1| 0| 1 +part2 | 1| 0| 1| 0 +(3 rows) -starting permutation: lock_access_exclusive vac_analyze_all_parts commit + +starting permutation: lock_access_exclusive vac_analyze_all_parts commit check_stat step lock_access_exclusive: BEGIN; LOCK part1 IN ACCESS EXCLUSIVE MODE; @@ -148,8 +330,22 @@ step commit: COMMIT; step vac_analyze_all_parts: <... completed> - -starting permutation: lock_access_exclusive vac_full_specified commit +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); + +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 1| 0 +part1 | 1| 0| 1| 0 +part2 | 1| 0| 1| 0 +(3 rows) + + +starting permutation: lock_access_exclusive vac_full_specified commit check_stat step lock_access_exclusive: BEGIN; LOCK part1 IN ACCESS EXCLUSIVE MODE; @@ -159,8 +355,22 @@ step vac_full_specified: VACUUM (SKIP_LOCKED, FULL) part1, part2; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); -starting permutation: lock_access_exclusive vac_full_all_parts commit +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 0| 0 +part1 | 0| 0| 0| 0 +part2 | 0| 0| 0| 0 +(3 rows) + + +starting permutation: lock_access_exclusive vac_full_all_parts commit check_stat step lock_access_exclusive: BEGIN; LOCK part1 IN ACCESS EXCLUSIVE MODE; @@ -169,3 +379,17 @@ step vac_full_all_parts: VACUUM (SKIP_LOCKED, FULL) parted; step commit: COMMIT; +step check_stat: + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); + +relname|vacuum_count|skipped_vacuum_count|analyze_count|skipped_analyze_count +-------+------------+--------------------+-------------+--------------------- +parted | 0| 0| 0| 0 +part1 | 0| 0| 0| 0 +part2 | 0| 0| 0| 0 +(3 rows) + diff --git a/src/test/isolation/specs/vacuum-skip-locked.spec b/src/test/isolation/specs/vacuum-skip-locked.spec index 3fad6e1c92a..b0da75d4b6d 100644 --- a/src/test/isolation/specs/vacuum-skip-locked.spec +++ b/src/test/isolation/specs/vacuum-skip-locked.spec @@ -33,6 +33,15 @@ step commit COMMIT; } +step check_stat +{ + SELECT relname, + vacuum_count, skipped_vacuum_count, + analyze_count, skipped_analyze_count + FROM pg_stat_all_tables + WHERE relname IN ('parted', 'part1', 'part2'); +} + session s2 step vac_specified { VACUUM (SKIP_LOCKED) part1, part2; } step vac_all_parts { VACUUM (SKIP_LOCKED) parted; } @@ -43,19 +52,19 @@ step vac_analyze_all_parts { VACUUM (ANALYZE, SKIP_LOCKED) parted; } step vac_full_specified { VACUUM (SKIP_LOCKED, FULL) part1, part2; } step vac_full_all_parts { VACUUM (SKIP_LOCKED, FULL) parted; } -permutation lock_share vac_specified commit -permutation lock_share vac_all_parts commit -permutation lock_share analyze_specified commit -permutation lock_share analyze_all_parts commit -permutation lock_share vac_analyze_specified commit -permutation lock_share vac_analyze_all_parts commit -permutation lock_share vac_full_specified commit -permutation lock_share vac_full_all_parts commit -permutation lock_access_exclusive vac_specified commit -permutation lock_access_exclusive vac_all_parts commit -permutation lock_access_exclusive analyze_specified commit -permutation lock_access_exclusive analyze_all_parts commit -permutation lock_access_exclusive vac_analyze_specified commit -permutation lock_access_exclusive vac_analyze_all_parts commit -permutation lock_access_exclusive vac_full_specified commit -permutation lock_access_exclusive vac_full_all_parts commit +permutation lock_share vac_specified commit check_stat +permutation lock_share vac_all_parts commit check_stat +permutation lock_share analyze_specified commit check_stat +permutation lock_share analyze_all_parts commit check_stat +permutation lock_share vac_analyze_specified commit check_stat +permutation lock_share vac_analyze_all_parts commit check_stat +permutation lock_share vac_full_specified commit check_stat +permutation lock_share vac_full_all_parts commit check_stat +permutation lock_access_exclusive vac_specified commit check_stat +permutation lock_access_exclusive vac_all_parts commit check_stat +permutation lock_access_exclusive analyze_specified commit check_stat +permutation lock_access_exclusive analyze_all_parts commit check_stat +permutation lock_access_exclusive vac_analyze_specified commit check_stat +permutation lock_access_exclusive vac_analyze_all_parts commit check_stat +permutation lock_access_exclusive vac_full_specified commit check_stat +permutation lock_access_exclusive vac_full_all_parts commit check_stat diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index a65a5bf0c4f..9b2075d3373 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1835,13 +1835,21 @@ pg_stat_all_tables| SELECT c.oid AS relid, pg_stat_get_mod_since_analyze(c.oid) AS n_mod_since_analyze, pg_stat_get_ins_since_vacuum(c.oid) AS n_ins_since_vacuum, pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum, + pg_stat_get_last_skipped_vacuum_time(c.oid) AS last_skipped_vacuum, pg_stat_get_last_autovacuum_time(c.oid) AS last_autovacuum, + pg_stat_get_last_skipped_autovacuum_time(c.oid) AS last_skipped_autovacuum, pg_stat_get_last_analyze_time(c.oid) AS last_analyze, + pg_stat_get_last_skipped_analyze_time(c.oid) AS last_skipped_analyze, pg_stat_get_last_autoanalyze_time(c.oid) AS last_autoanalyze, + pg_stat_get_last_skipped_autoanalyze_time(c.oid) AS last_skipped_autoanalyze, pg_stat_get_vacuum_count(c.oid) AS vacuum_count, + pg_stat_get_skipped_vacuum_count(c.oid) AS skipped_vacuum_count, pg_stat_get_autovacuum_count(c.oid) AS autovacuum_count, + pg_stat_get_skipped_autovacuum_count(c.oid) AS skipped_autovacuum_count, pg_stat_get_analyze_count(c.oid) AS analyze_count, + pg_stat_get_skipped_analyze_count(c.oid) AS skipped_analyze_count, pg_stat_get_autoanalyze_count(c.oid) AS autoanalyze_count, + pg_stat_get_skipped_autoanalyze_count(c.oid) AS skipped_autoanalyze_count, pg_stat_get_total_vacuum_time(c.oid) AS total_vacuum_time, pg_stat_get_total_autovacuum_time(c.oid) AS total_autovacuum_time, pg_stat_get_total_analyze_time(c.oid) AS total_analyze_time, @@ -2346,13 +2354,21 @@ pg_stat_sys_tables| SELECT relid, n_mod_since_analyze, n_ins_since_vacuum, last_vacuum, + last_skipped_vacuum, last_autovacuum, + last_skipped_autovacuum, last_analyze, + last_skipped_analyze, last_autoanalyze, + last_skipped_autoanalyze, vacuum_count, + skipped_vacuum_count, autovacuum_count, + skipped_autovacuum_count, analyze_count, + skipped_analyze_count, autoanalyze_count, + skipped_autoanalyze_count, total_vacuum_time, total_autovacuum_time, total_analyze_time, @@ -2401,13 +2417,21 @@ pg_stat_user_tables| SELECT relid, n_mod_since_analyze, n_ins_since_vacuum, last_vacuum, + last_skipped_vacuum, last_autovacuum, + last_skipped_autovacuum, last_analyze, + last_skipped_analyze, last_autoanalyze, + last_skipped_autoanalyze, vacuum_count, + skipped_vacuum_count, autovacuum_count, + skipped_autovacuum_count, analyze_count, + skipped_analyze_count, autoanalyze_count, + skipped_autoanalyze_count, total_vacuum_time, total_autovacuum_time, total_analyze_time, -- 2.43.0 --Multipart=_Mon__27_Apr_2026_20_32_07_+0900_jUJUG74bF5asMQ6P-- ^ permalink raw reply [nested|flat] 267+ messages in thread
end of thread, other threads:[~2026-03-24 04:09 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-24 04:09 [PATCH v5] Track skipped vacuum and analyze activity per relation Yugo Nagata <[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