agora inbox for [email protected]
help / color / mirror / Atom feedIncorrect comments in partition.c
269+ messages / 3 participants
[nested] [flat]
* Incorrect comments in partition.c
@ 2018-01-23 11:43 Etsuro Fujita <[email protected]>
2018-01-24 04:06 ` Re: Incorrect comments in partition.c Amit Langote <[email protected]>
0 siblings, 1 reply; 269+ messages in thread
From: Etsuro Fujita @ 2018-01-23 11:43 UTC (permalink / raw)
To: [email protected]
Here is a comment for get_qual_for_list in partition.c:
* get_qual_for_list
*
* Returns an implicit-AND list of expressions to use as a list partition's
- * constraint, given the partition key and bound structures.
I don't think the part "given the partition key and bound structures."
is correct because we pass the *parent relation* and partition bound
structure to that function. So I think we should change that part as
such. get_qual_for_range has the same issue, so I think we need this
change for that function as well.
Another one I noticed in comments in partition.c is:
* get_qual_for_hash
*
* Given a list of partition columns, modulus and remainder
corresponding to a
* partition, this function returns CHECK constraint expression Node for
that
* partition.
I think the part "Given a list of partition columns, modulus and
remainder corresponding to a partition" is wrong because we pass to that
function the parent relation and partition bound structure the same way
as for get_qual_for_list/get_qual_for_range. So what about changing the
above to something like this, similarly to
get_qual_for_list/get_qual_for_range:
Returns a CHECK constraint expression to use as a hash partition's
constraint, given the parent relation and partition bound structure.
Also:
* The partition constraint for a hash partition is always a call to the
* built-in function satisfies_hash_partition(). The first two
arguments are
* the modulus and remainder for the partition; the remaining arguments
are the
* values to be hashed.
I also think the part "The first two arguments are the modulus and
remainder for the partition;" is wrong (see satisfies_hash_partition).
But I don't think we need to correct that here because we have described
about the arguments in comments for that function. So I'd like to
propose removing the latter comment entirely from the above.
Attached is a proposed patch for that.
Best regards,
Etsuro Fujita
Attachments:
[text/x-diff] partition-comments.patch (2.6K, ../../[email protected]/2-partition-comments.patch)
download | inline diff:
*** a/src/backend/catalog/partition.c
--- b/src/backend/catalog/partition.c
***************
*** 1660,1673 **** make_partition_op_expr(PartitionKey key, int keynum,
/*
* get_qual_for_hash
*
! * Given a list of partition columns, modulus and remainder corresponding to a
! * partition, this function returns CHECK constraint expression Node for that
! * partition.
*
* The partition constraint for a hash partition is always a call to the
! * built-in function satisfies_hash_partition(). The first two arguments are
! * the modulus and remainder for the partition; the remaining arguments are the
! * values to be hashed.
*/
static List *
get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
--- 1660,1670 ----
/*
* get_qual_for_hash
*
! * Returns a CHECK constraint expression to use as a hash partition's
! * constraint, given the parent relation and partition bound structure.
*
* The partition constraint for a hash partition is always a call to the
! * built-in function satisfies_hash_partition().
*/
static List *
get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
***************
*** 1747,1753 **** get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
* get_qual_for_list
*
* Returns an implicit-AND list of expressions to use as a list partition's
! * constraint, given the partition key and bound structures.
*
* The function returns NIL for a default partition when it's the only
* partition since in that case there is no constraint.
--- 1744,1750 ----
* get_qual_for_list
*
* Returns an implicit-AND list of expressions to use as a list partition's
! * constraint, given the parent relation and partition bound structure.
*
* The function returns NIL for a default partition when it's the only
* partition since in that case there is no constraint.
***************
*** 2027,2033 **** get_range_nulltest(PartitionKey key)
* get_qual_for_range
*
* Returns an implicit-AND list of expressions to use as a range partition's
! * constraint, given the partition key and bound structures.
*
* For a multi-column range partition key, say (a, b, c), with (al, bl, cl)
* as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we
--- 2024,2030 ----
* get_qual_for_range
*
* Returns an implicit-AND list of expressions to use as a range partition's
! * constraint, given the parent relation and partition bound structure.
*
* For a multi-column range partition key, say (a, b, c), with (al, bl, cl)
* as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we
^ permalink raw reply [nested|flat] 269+ messages in thread
* Re: Incorrect comments in partition.c
2018-01-23 11:43 Incorrect comments in partition.c Etsuro Fujita <[email protected]>
@ 2018-01-24 04:06 ` Amit Langote <[email protected]>
2018-01-24 05:44 ` Re: Incorrect comments in partition.c Etsuro Fujita <[email protected]>
0 siblings, 1 reply; 269+ messages in thread
From: Amit Langote @ 2018-01-24 04:06 UTC (permalink / raw)
To: Etsuro Fujita <[email protected]>; [email protected]
On 2018/01/23 20:43, Etsuro Fujita wrote:
> Here is a comment for get_qual_for_list in partition.c:
>
> * get_qual_for_list
> *
> * Returns an implicit-AND list of expressions to use as a list partition's
> - * constraint, given the partition key and bound structures.
>
> I don't think the part "given the partition key and bound structures."
> is correct because we pass the *parent relation* and partition bound
> structure to that function. So I think we should change that part as
> such. get_qual_for_range has the same issue, so I think we need this
> change for that function as well.
Yeah. It seems 6f6b99d1335 [1] changed their signatures to support
handling default partitions.
> Another one I noticed in comments in partition.c is:
>
> * get_qual_for_hash
> *
> * Given a list of partition columns, modulus and remainder
> corresponding to a
> * partition, this function returns CHECK constraint expression Node for
> that
> * partition.
>
> I think the part "Given a list of partition columns, modulus and
> remainder corresponding to a partition" is wrong because we pass to that
> function the parent relation and partition bound structure the same way
> as for get_qual_for_list/get_qual_for_range. So what about changing the
> above to something like this, similarly to
> get_qual_for_list/get_qual_for_range:
>
> Returns a CHECK constraint expression to use as a hash partition's
> constraint, given the parent relation and partition bound structure.
Makes sense.
> Also:
>
> * The partition constraint for a hash partition is always a call to the
> * built-in function satisfies_hash_partition(). The first two
> arguments are
> * the modulus and remainder for the partition; the remaining arguments
> are the
> * values to be hashed.
>
> I also think the part "The first two arguments are the modulus and
> remainder for the partition;" is wrong (see satisfies_hash_partition).
> But I don't think we need to correct that here because we have described
> about the arguments in comments for that function. So I'd like to
> propose removing the latter comment entirely from the above.
Here, too. The comment seems to have been obsoleted by f3b0897a121 [2].
Thanks,
Amit
[1] https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=6f6b99d1335
[2] https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=f3b0897a121
^ permalink raw reply [nested|flat] 269+ messages in thread
* Re: Incorrect comments in partition.c
2018-01-23 11:43 Incorrect comments in partition.c Etsuro Fujita <[email protected]>
2018-01-24 04:06 ` Re: Incorrect comments in partition.c Amit Langote <[email protected]>
@ 2018-01-24 05:44 ` Etsuro Fujita <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Etsuro Fujita @ 2018-01-24 05:44 UTC (permalink / raw)
To: Amit Langote <[email protected]>; +Cc: [email protected]
(2018/01/24 13:06), Amit Langote wrote:
> On 2018/01/23 20:43, Etsuro Fujita wrote:
>> Here is a comment for get_qual_for_list in partition.c:
>>
>> * get_qual_for_list
>> *
>> * Returns an implicit-AND list of expressions to use as a list partition's
>> - * constraint, given the partition key and bound structures.
>>
>> I don't think the part "given the partition key and bound structures."
>> is correct because we pass the *parent relation* and partition bound
>> structure to that function. So I think we should change that part as
>> such. get_qual_for_range has the same issue, so I think we need this
>> change for that function as well.
>
> Yeah. It seems 6f6b99d1335 [1] changed their signatures to support
> handling default partitions.
>
>> Another one I noticed in comments in partition.c is:
>>
>> * get_qual_for_hash
>> *
>> * Given a list of partition columns, modulus and remainder
>> corresponding to a
>> * partition, this function returns CHECK constraint expression Node for
>> that
>> * partition.
>>
>> I think the part "Given a list of partition columns, modulus and
>> remainder corresponding to a partition" is wrong because we pass to that
>> function the parent relation and partition bound structure the same way
>> as for get_qual_for_list/get_qual_for_range. So what about changing the
>> above to something like this, similarly to
>> get_qual_for_list/get_qual_for_range:
>>
>> Returns a CHECK constraint expression to use as a hash partition's
>> constraint, given the parent relation and partition bound structure.
>
> Makes sense.
>
>> Also:
>>
>> * The partition constraint for a hash partition is always a call to the
>> * built-in function satisfies_hash_partition(). The first two
>> arguments are
>> * the modulus and remainder for the partition; the remaining arguments
>> are the
>> * values to be hashed.
>>
>> I also think the part "The first two arguments are the modulus and
>> remainder for the partition;" is wrong (see satisfies_hash_partition).
>> But I don't think we need to correct that here because we have described
>> about the arguments in comments for that function. So I'd like to
>> propose removing the latter comment entirely from the above.
>
> Here, too. The comment seems to have been obsoleted by f3b0897a121 [2].
Thanks for the review and related git info!
Best regards,
Etsuro Fujita
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
* [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup.
@ 2024-05-18 01:41 Thomas Munro <[email protected]>
0 siblings, 0 replies; 269+ messages in thread
From: Thomas Munro @ 2024-05-18 01:41 UTC (permalink / raw)
When backend processes were launched in EXEC_BACKEND builds, they would
run LocalProcessControlFile() to read in pg_control and extract several
important settings.
This happens too early to acquire ControlFileLock, and the postmaster is
also not allowed to acquire ControlFileLock, so it can't safely take a
copy to give to the child.
Instead, pass down the "proto-controlfile" that was read by the
postmaster in LocalProcessControlFile(). Introduce functions
ExportProtoControlFile() and ImportProtoControlFile() to allow that.
Subprocesses will extract information from that, and then later attach
to the current control file in shared memory.
Reported-by: Melanie Plageman <[email protected]> per Windows CI failure
Discussion: https://postgr.es/m/CAAKRu_YNGwEYrorQYza_W8tU%2B%3DtoXRHG8HpyHC-KDbZqA_ZVSA%40mail.gmail.com
---
src/backend/access/transam/xlog.c | 46 +++++++++++++++++++++++--
src/backend/postmaster/launch_backend.c | 21 +++++++----
src/include/access/xlog.h | 5 +++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 13ec6225b85..e52517eb9c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -575,6 +575,10 @@ static WALInsertLockPadded *WALInsertLocks = NULL;
*/
static ControlFileData *ControlFile = NULL;
+#ifdef EXEC_BACKEND
+static ControlFileData *ProtoControlFile = NULL;
+#endif
+
/*
* Calculate the amount of space left on the page after 'endptr'. Beware
* multiple evaluation!
@@ -692,6 +696,7 @@ static bool PerformRecoveryXLogAction(void);
static void InitControlFile(uint64 sysidentifier, uint32 data_checksum_version);
static void WriteControlFile(void);
static void ReadControlFile(void);
+static void ScanControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow, char *buf, size_t bufsize);
@@ -4385,9 +4390,7 @@ WriteControlFile(void)
static void
ReadControlFile(void)
{
- pg_crc32c crc;
int fd;
- char wal_segsz_str[20];
int r;
/*
@@ -4420,6 +4423,15 @@ ReadControlFile(void)
close(fd);
+ ScanControlFile();
+}
+
+static void
+ScanControlFile(void)
+{
+ static char wal_segsz_str[20];
+ pg_crc32c crc;
+
/*
* Check for expected pg_control format version. If this is wrong, the
* CRC check will likely fail because we'll be checking the wrong number
@@ -4941,8 +4953,33 @@ LocalProcessControlFile(bool reset)
Assert(reset || ControlFile == NULL);
ControlFile = palloc_object(ControlFileData);
ReadControlFile();
+
+#ifdef EXEC_BACKEND
+ /* We need to be able to give this to subprocesses. */
+ ProtoControlFile = ControlFile;
+#endif
}
+#ifdef EXEC_BACKEND
+void
+ExportProtoControlFile(ControlFileData *copy)
+{
+ *copy = *ProtoControlFile;
+}
+
+/*
+ * Like LocalProcessControlFile(), but used early in EXEC_BACKEND children's
+ * startup. This receives the same file that the postmaster first read.
+ */
+void
+ImportProtoControlFile(const ControlFileData *copy)
+{
+ ControlFile = palloc(sizeof(ControlFileData));
+ *ControlFile = *copy;
+ ScanControlFile();
+}
+#endif
+
/*
* Get the wal_level from the control file. For a standby, this value should be
* considered as its active wal_level, because it may be different from what
@@ -5061,7 +5098,12 @@ XLOGShmemInit(void)
if (localControlFile)
{
memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+#ifdef EXEC_BACKEND
+ /* We still hold a reference to give to subprocesses. */
+ Assert(ProtoControlFile == localControlFile);
+#else
pfree(localControlFile);
+#endif
}
/*
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 45690b11c99..e08a405f949 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -33,6 +33,9 @@
#include <unistd.h>
+#include "access/xlog.h"
+#include "catalog/pg_control.h"
+#include "common/file_utils.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
@@ -133,6 +136,14 @@ typedef struct
int MyPMChildSlot;
+ /*
+ * A copy of the ControlFileData from early in Postmaster startup. We
+ * need to access its contents it at a phase of initialization before we
+ * are allowed to acquire LWLocks, so we can't just use shared memory or
+ * read the file from disk.
+ */
+ ControlFileData proto_controlfile;
+
/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
@@ -659,12 +670,6 @@ SubPostmasterMain(int argc, char *argv[])
*/
checkDataDir();
- /*
- * (re-)read control file, as it contains config. The postmaster will
- * already have read this, but this process doesn't know about that.
- */
- LocalProcessControlFile(false);
-
/*
* Reload any libraries that were preloaded by the postmaster. Since we
* exec'd this process, those libraries didn't come along with us; but we
@@ -752,6 +757,8 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;
+ ExportProtoControlFile(¶m->proto_controlfile);
+
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(¶m->initial_signal_pipe,
@@ -1026,6 +1033,8 @@ restore_backend_variables(BackendParameters *param)
strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+ ImportProtoControlFile(¶m->proto_controlfile);
+
/*
* We need to restore fd.c's counts of externally-opened FDs; to avoid
* confusion, be sure to do this after restoring max_safe_fds. (Note:
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..f1f3ad4e96e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -208,6 +208,7 @@ typedef enum WALAvailability
struct XLogRecData;
struct XLogReaderState;
+struct ControlFileData;
extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
XLogRecPtr fpw_lsn,
@@ -250,6 +251,10 @@ extern void XLOGShmemInit(void);
extern void BootStrapXLOG(uint32 data_checksum_version);
extern void InitializeWalConsistencyChecking(void);
extern void LocalProcessControlFile(bool reset);
+#ifdef EXEC_BACKEND
+extern void ExportProtoControlFile(struct ControlFileData *copy);
+extern void ImportProtoControlFile(const struct ControlFileData *copy);
+#endif
extern WalLevel GetActiveWalLevelOnStandby(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(int code, Datum arg);
--
2.47.3
--dhbc6bswyy6qufwn--
^ permalink raw reply [nested|flat] 269+ messages in thread
end of thread, other threads:[~2024-05-18 01:41 UTC | newest]
Thread overview: 269+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2018-01-23 11:43 Incorrect comments in partition.c Etsuro Fujita <[email protected]>
2018-01-24 04:06 ` Amit Langote <[email protected]>
2018-01-24 05:44 ` Etsuro Fujita <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[email protected]>
2024-05-18 01:41 [PATCH v2] Fix pg_control corruption in EXEC_BACKEND startup. Thomas Munro <[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